SCIP Doxygen Documentation
Loading...
Searching...
No Matches
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-2026 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 "tclique/tclique.h"
55#include "scip/cons_linking.h"
56#include "scip/cons_knapsack.h"
57#include "scip/scipdefplugins.h"
58
59/**@name Constraint handler properties
60 *
61 * @{
62 */
63
64/* constraint handler properties */
65#define CONSHDLR_NAME "cumulative"
66#define CONSHDLR_DESC "cumulative constraint handler"
67#define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
68#define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
69#define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
70#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
71#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
72#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
73 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
74#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
75#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
76#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
77#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
78
79#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
80#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
81
82/**@} */
83
84/**@name Default parameter values
85 *
86 * @{
87 */
88
89/* default parameter values */
90#define DEFAULT_MAXTIME 2000000000 /** < maximum range for time horizon (to avoid integer overflow) */
91
92/* separation */
93#define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
94#define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
95#define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
96#define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
97#define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
98
99/* propagation */
100#define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
101#define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
102#define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
103#define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
104#define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
105#define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
106
107/* presolving */
108#define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
109#define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
110#define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
111#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
112#define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
113#define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
114#define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
115#define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
116
117/* enforcement */
118#define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
119
120/* conflict analysis */
121#define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
122
123/**@} */
124
125/**@name Event handler properties
126 *
127 * @{
128 */
129
130#define EVENTHDLR_NAME "cumulative"
131#define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
132
133/**@} */
134
135/*
136 * Data structures
137 */
138
139/** constraint data for cumulative constraints */
140struct SCIP_ConsData
141{
142 SCIP_VAR** vars; /**< array of variable representing the start time of each job */
143 SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
144 SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
145 SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
146 SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
147 SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
148 SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
149 int* demands; /**< array containing corresponding demands */
150 int* durations; /**< array containing corresponding durations */
151 SCIP_Real resstrength1; /**< stores the resource strength 1*/
152 SCIP_Real resstrength2; /**< stores the resource strength 2 */
153 SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
154 SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
155 SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
156 SCIP_Real estimatedstrength;
157 int nvars; /**< number of variables */
158 int varssize; /**< size of the arrays */
159 int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
160 int demandrowssize; /**< size of array rows of demand rows */
161 int nscoverrows; /**< number of rows of small cover cuts */
162 int scoverrowssize; /**< size of array of small cover cuts */
163 int nbcoverrows; /**< number of rows of big cover cuts */
164 int bcoverrowssize; /**< size of array of big cover cuts */
165 int capacity; /**< available cumulative capacity */
166
167 int hmin; /**< left bound of time axis to be considered (including hmin) */
168 int hmax; /**< right bound of time axis to be considered (not including hmax) */
169
170 unsigned int signature; /**< constraint signature which is need for pairwise comparison */
171
172 unsigned int validsignature:1; /**< is the signature valid */
173 unsigned int normalized:1; /**< is the constraint normalized */
174 unsigned int covercuts:1; /**< cover cuts are created? */
175 unsigned int propagated:1; /**< is constraint propagted */
176 unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
177 unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
178
179#ifdef SCIP_STATISTIC
180 int maxpeak;
181#endif
182};
183
184/** constraint handler data */
185struct SCIP_ConshdlrData
186{
187 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
188
189 SCIP_Bool usebinvars; /**< should the binary variables be used? */
190 SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
191 SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
192 SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
193 SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
194 SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
195 SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
196 SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
197 SCIP_Bool localcuts; /**< should cuts be added only locally? */
198 SCIP_Bool usecovercuts; /**< should covering cuts be added? */
199 SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
200
201 SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
202
203 SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
204 SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
205 SCIP_Bool normalize; /**< should demands and capacity be normalized? */
206 SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
207 SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
208 SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
209 SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
210 SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
211 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
212
213 int maxtime; /**< maximum range for time horizon (to avoid integer overflow) */
214 SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
215
216 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
217
218 /* statistic values which are collected if SCIP_STATISTIC is defined */
219#ifdef SCIP_STATISTIC
220 SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
221 SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
222 SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
223 SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
224 SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
225 SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
226 SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
227 SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
228 SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
229 SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
230
231 int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
232 int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
233 int nremovedlocks; /**< number of times a up or down lock was removed */
234 int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
235 int ndecomps; /**< number of times a constraint was decomposed */
236 int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
237 int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
238 int naddedvarbounds; /**< number of added variable bounds constraints */
239 int naddeddisjunctives; /**< number of added disjunctive constraints */
240
241 SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
242#endif
243};
244
245/**@name Inference Information Methods
246 *
247 * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
248 * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
249 * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
250 *
251 * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
252 * change and the earliest start and latest completion time of all jobs in the conflict set.
253 *
254 * @{
255 */
256
257/** Propagation rules */
259{
260 PROPRULE_0_INVALID = 0, /**< invalid inference information */
261 PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
262 PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
263 PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
264};
265typedef enum Proprule PROPRULE;
266
267/** inference information */
268struct InferInfo
269{
270 union
271 {
272 /** struct to use the inference information */
273 struct
274 {
275 unsigned int proprule:2; /**< propagation rule that was applied */
276 unsigned int data1:15; /**< data field one */
277 unsigned int data2:15; /**< data field two */
278 } asbits;
279 int asint; /**< inference information as a single int value */
280 } val;
281};
282typedef struct InferInfo INFERINFO;
283
284/** converts an integer into an inference information */
285static
287 int i /**< integer to convert */
288 )
289{
290 INFERINFO inferinfo;
291
292 inferinfo.val.asint = i;
293
294 return inferinfo;
295}
296
297/** converts an inference information into an int */
298static
300 INFERINFO inferinfo /**< inference information to convert */
301 )
302{
303 return inferinfo.val.asint;
304}
305
306/** rounds real to int and maps for large absolute values */
307static
309 SCIP* scip, /**< scip data structure */
310 SCIP_Real real /**< double bound to convert */
311 )
312{
313 int maxval;
314
316
317 assert(maxval >= 0);
318
319 if( SCIPisInfinity(scip, real) || real > maxval )
320 {
321 return maxval;
322 }
323 if( SCIPisInfinity(scip, -real) || real < -maxval )
324 {
325 return -maxval;
326 }
328}
329
330/** returns the propagation rule stored in the inference information */
331static
333 INFERINFO inferinfo /**< inference information to convert */
334 )
335{
336 return (PROPRULE) inferinfo.val.asbits.proprule;
337}
338
339/** returns data field one of the inference information */
340static
342 INFERINFO inferinfo /**< inference information to convert */
343 )
344{
345 return (int) inferinfo.val.asbits.data1;
346}
347
348/** returns data field two of the inference information */
349static
351 INFERINFO inferinfo /**< inference information to convert */
352 )
353{
354 return (int) inferinfo.val.asbits.data2;
355}
356
357/** returns whether the inference information is valid */
358static
360 INFERINFO inferinfo /**< inference information to convert */
361 )
362{
363 return (inferinfo.val.asint != 0);
364}
365
366
367/** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
368static
370 PROPRULE proprule, /**< propagation rule that deduced the value */
371 int data1, /**< data field one */
372 int data2 /**< data field two */
373 )
374{
375 INFERINFO inferinfo;
376
377 /* check that the data members are in the range of the available bits */
378 if( proprule == PROPRULE_0_INVALID || data1 < 0 || data1 >= (1<<15) || data2 < 0 || data2 >= (1<<15) )
379 {
380 inferinfo.val.asint = 0;
382 assert(inferInfoIsValid(inferinfo) == FALSE);
383 }
384 else
385 {
386 inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
387 inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
388 inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
389 assert(inferInfoIsValid(inferinfo) == TRUE);
390 }
391
392 return inferinfo;
393}
394
395/**@} */
396
397/*
398 * Local methods
399 */
400
401/**@name Miscellaneous Methods
402 *
403 * @{
404 */
405
406#ifndef NDEBUG
407
408/** compute the core of a job which lies in certain interval [begin, end) */
409static
411 int begin, /**< begin of the interval */
412 int end, /**< end of the interval */
413 int ect, /**< earliest completion time */
414 int lst /**< latest start time */
415 )
416{
417 int core;
418
419 core = MAX(0, MIN(end, ect) - MAX(lst, begin));
420
421 return core;
422}
423#else
424#define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
425#endif
426
427/** returns the implied earliest start time */ /*lint -e{715}*/
428static
430 SCIP* scip, /**< SCIP data structure */
431 SCIP_VAR* var, /**< variable for which the implied est should be returned */
432 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
433 int* est /**< pointer to store the implied earliest start time */
434 )
435{ /*lint --e{715}*/
436#ifdef SCIP_DISABLED_CODE
437 /* there is a bug below */
438 SCIP_VAR** vbdvars;
439 SCIP_VAR* vbdvar;
440 SCIP_Real* vbdcoefs;
441 SCIP_Real* vbdconsts;
442 void* image;
443 int nvbdvars;
444 int v;
445#endif
446
448
449#ifdef SCIP_DISABLED_CODE
450 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
451
452 nvbdvars = SCIPvarGetNVlbs(var);
453 vbdvars = SCIPvarGetVlbVars(var);
454 vbdcoefs = SCIPvarGetVlbCoefs(var);
455 vbdconsts = SCIPvarGetVlbConstants(var);
456
457 for( v = 0; v < nvbdvars; ++v )
458 {
459 vbdvar = vbdvars[v];
460 assert(vbdvar != NULL);
461
462 image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
463
464 if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
465 {
466 int duration;
467 int vbdconst;
468
469 duration = (int)(size_t)image;
470 vbdconst = boundedConvertRealToInt(scip, vbdconsts[v]);
471
472 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
474 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
475
476 if( duration >= vbdconst )
477 {
478 int impliedest;
479
480 impliedest = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
481
482 if( (*est) < impliedest )
483 {
484 (*est) = impliedest;
485
486 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
487 }
488 }
489 }
490 }
491#endif
492
493 return SCIP_OKAY;
494}
495
496/** returns the implied latest completion time */ /*lint -e{715}*/
497static
499 SCIP* scip, /**< SCIP data structure */
500 SCIP_VAR* var, /**< variable for which the implied est should be returned */
501 int duration, /**< duration of the given job */
502 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
503 int* lct /**< pointer to store the implied latest completion time */
504 )
505{ /*lint --e{715}*/
506#ifdef SCIP_DISABLED_CODE
507 /* there is a bug below */
508 SCIP_VAR** vbdvars;
509 SCIP_VAR* vbdvar;
510 SCIP_Real* vbdcoefs;
511 SCIP_Real* vbdconsts;
512 int nvbdvars;
513 int v;
514#endif
515
516 (*lct) = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
517
518#ifdef SCIP_DISABLED_CODE
519 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
520
521 nvbdvars = SCIPvarGetNVubs(var);
522 vbdvars = SCIPvarGetVubVars(var);
523 vbdcoefs = SCIPvarGetVubCoefs(var);
524 vbdconsts = SCIPvarGetVubConstants(var);
525
526 for( v = 0; v < nvbdvars; ++v )
527 {
528 vbdvar = vbdvars[v];
529 assert(vbdvar != NULL);
530
531 if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
532 {
533 int vbdconst;
534
535 vbdconst = boundedConvertRealToInt(scip, -vbdconsts[v]);
536
537 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
539 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
540
541 if( duration >= -vbdconst )
542 {
543 int impliedlct;
544
545 impliedlct = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
546
547 if( (*lct) > impliedlct )
548 {
549 (*lct) = impliedlct;
550
551 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
552 }
553 }
554 }
555 }
556#endif
557
558 return SCIP_OKAY;
559}
560
561/** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
562static
564 SCIP* scip, /**< SCIP data structure */
565 SCIP_CONSDATA* consdata, /**< constraint data */
566 SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
567 int** coefs, /**< pointer to store the coefficients */
568 int* nvars, /**< number if collect binary variables */
569 int* startindices, /**< permutation with rspect to the start times */
570 int curtime, /**< current point in time */
571 int nstarted, /**< number of jobs that start before the curtime or at curtime */
572 int nfinished /**< number of jobs that finished before curtime or at curtime */
573 )
574{
575 int nrowvars;
576 int startindex;
577 int size;
578
579 size = 10;
580 nrowvars = 0;
581 startindex = nstarted - 1;
582
584 SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
585
586 /* search for the (nstarted - nfinished) jobs which are active at curtime */
587 while( nstarted - nfinished > nrowvars )
588 {
589 SCIP_VAR* var;
590 int endtime;
591 int duration;
592 int demand;
593 int varidx;
594
595 /* collect job information */
596 varidx = startindices[startindex];
598
599 var = consdata->vars[varidx];
600 duration = consdata->durations[varidx];
601 demand = consdata->demands[varidx];
602 assert(var != NULL);
603
604 endtime = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
605
606 /* check the end time of this job is larger than the curtime; in this case the job is still running */
607 if( endtime > curtime )
608 {
609 SCIP_VAR** binvars;
610 SCIP_Real* vals;
611 int nbinvars;
612 int start;
613 int end;
614 int b;
615
616 /* check if the linking constraints exists */
619 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
620
621 /* collect linking constraint information */
622 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
623 vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
624
625 start = curtime - duration + 1;
626 end = MIN(curtime, endtime - duration);
627
628 for( b = 0; b < nbinvars; ++b )
629 {
630 if( vals[b] < start )
631 continue;
632
633 if( vals[b] > end )
634 break;
635
636 assert(binvars[b] != NULL);
637
638 /* ensure array proper array size */
639 if( size == *nvars )
640 {
641 size *= 2;
643 SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
644 }
645
646 (*vars)[*nvars] = binvars[b];
647 (*coefs)[*nvars] = demand;
648 (*nvars)++;
649 }
650 nrowvars++;
651 }
652
653 startindex--;
654 }
655
656 return SCIP_OKAY;
657}
658
659/** collect all integer variable which belong to jobs which can run at the point of interest */
660static
662 SCIP* scip, /**< SCIP data structure */
663 SCIP_CONSDATA* consdata, /**< constraint data */
664 SCIP_VAR*** activevars, /**< jobs that are currently running */
665 int* startindices, /**< permutation with rspect to the start times */
666 int curtime, /**< current point in time */
667 int nstarted, /**< number of jobs that start before the curtime or at curtime */
668 int nfinished, /**< number of jobs that finished before curtime or at curtime */
669 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
670 int* lhs /**< lhs for the new row sum of lbs + minoffset */
671 )
672{
673 SCIP_VAR* var;
674 int startindex;
675 int endtime;
676 int duration;
677 int starttime;
678
679 int varidx;
680 int sumofstarts;
681 int mindelta;
682 int counter;
683
684 assert(curtime >= consdata->hmin);
685 assert(curtime < consdata->hmax);
686
687 counter = 0;
688 sumofstarts = 0;
689
690 mindelta = INT_MAX;
691
692 startindex = nstarted - 1;
693
694 /* search for the (nstarted - nfinished) jobs which are active at curtime */
695 while( nstarted - nfinished > counter )
696 {
697 assert(startindex >= 0);
698
699 /* collect job information */
700 varidx = startindices[startindex];
702
703 var = consdata->vars[varidx];
704 duration = consdata->durations[varidx];
705 assert(duration > 0);
706 assert(var != NULL);
707
708 if( lower )
710 else
712
713 endtime = MIN(starttime + duration, consdata->hmax);
714
715 /* check the end time of this job is larger than the curtime; in this case the job is still running */
716 if( endtime > curtime )
717 {
718 (*activevars)[counter] = var;
719 sumofstarts += starttime;
720 mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
721 counter++;
722 }
723
724 startindex--;
725 }
726
727 assert(mindelta > 0);
728 *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
729
730 return SCIP_OKAY;
731}
732
733/** initialize the sorted event point arrays */
734static
736 SCIP* scip, /**< SCIP data structure */
737 int nvars, /**< number of start time variables (activities) */
738 SCIP_VAR** vars, /**< array of start time variables */
739 int* durations, /**< array of durations per start time variable */
740 int* starttimes, /**< array to store sorted start events */
741 int* endtimes, /**< array to store sorted end events */
742 int* startindices, /**< permutation with rspect to the start times */
743 int* endindices, /**< permutation with rspect to the end times */
744 SCIP_Bool local /**< shall local bounds be used */
745 )
746{
747 SCIP_VAR* var;
748 int j;
749
750 assert(vars != NULL || nvars == 0);
751
752 /* assign variables, start and endpoints to arrays */
753 for ( j = 0; j < nvars; ++j )
754 {
755 assert(vars != NULL);
756
757 var = vars[j];
758 assert(var != NULL);
759
760 if( local )
762 else
764
765 startindices[j] = j;
766
767 if( local )
768 endtimes[j] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
769 else
770 endtimes[j] = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
771
772 endindices[j] = j;
773 }
774
775 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
776 SCIPsortIntInt(starttimes, startindices, j);
777 SCIPsortIntInt(endtimes, endindices, j);
778}
779
780/** initialize the sorted event point arrays w.r.t. the given primal solutions */
781static
783 SCIP* scip, /**< SCIP data structure */
784 SCIP_SOL* sol, /**< solution */
785 int nvars, /**< number of start time variables (activities) */
786 SCIP_VAR** vars, /**< array of start time variables */
787 int* durations, /**< array of durations per start time variable */
788 int* starttimes, /**< array to store sorted start events */
789 int* endtimes, /**< array to store sorted end events */
790 int* startindices, /**< permutation with rspect to the start times */
791 int* endindices /**< permutation with rspect to the end times */
792 )
793{
794 SCIP_VAR* var;
795 int j;
796
797 assert(vars != NULL || nvars == 0);
798
799 /* assign variables, start and endpoints to arrays */
800 for ( j = 0; j < nvars; ++j )
801 {
802 assert(vars != NULL);
803
804 var = vars[j];
805 assert(var != NULL);
806
808 startindices[j] = j;
809
810 endtimes[j] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
811 endindices[j] = j;
812 }
813
814 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
815 SCIPsortIntInt(starttimes, startindices, j);
816 SCIPsortIntInt(endtimes, endindices, j);
817}
818
819/** initialize the sorted event point arrays
820 *
821 * @todo Check the separation process!
822 */
823static
825 SCIP* scip, /**< SCIP data structure */
826 SCIP_CONSDATA* consdata, /**< constraint data */
827 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
828 int* starttimes, /**< array to store sorted start events */
829 int* endtimes, /**< array to store sorted end events */
830 int* startindices, /**< permutation with rspect to the start times */
831 int* endindices, /**< permutation with rspect to the end times */
832 int* nvars, /**< number of variables that are integral */
833 SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
834 )
835{
836 SCIP_VAR* var;
837 int tmpnvars;
838 int j;
839
840 tmpnvars = consdata->nvars;
841 *nvars = 0;
842
843 /* assign variables, start and endpoints to arrays */
844 for ( j = 0; j < tmpnvars; ++j )
845 {
846 var = consdata->vars[j];
847 assert(var != NULL);
848 assert(consdata->durations[j] > 0);
849 assert(consdata->demands[j] > 0);
850
851 if( lower )
852 {
853 /* only consider jobs that are at their lower or upper bound */
856 continue;
857
859 startindices[*nvars] = j;
860
861 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
862 endindices[*nvars] = j;
863
864 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
866 consdata->durations[j],
867 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
868 consdata->demands[startindices[*nvars]]);
869
870 (*nvars)++;
871 }
872 else
873 {
876 continue;
877
879 startindices[*nvars] = j;
880
881 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
882 endindices[*nvars] = j;
883
884 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
886 consdata->durations[j],
887 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
888 consdata->demands[startindices[*nvars]]);
889
890 (*nvars)++;
891 }
892 }
893
894 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
895 SCIPsortIntInt(starttimes, startindices, *nvars);
896 SCIPsortIntInt(endtimes, endindices, *nvars);
897
898#ifdef SCIP_DEBUG
899 SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
900
901 for ( j = 0; j < *nvars; ++j )
902 {
903 SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
904 startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
905 consdata->demands[startindices[j]]);
906 }
907
908 for ( j = 0; j < *nvars; ++j )
909 {
910 SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
911 consdata->demands[endindices[j]]);
912 }
913#endif
914}
915
916#ifdef SCIP_STATISTIC
917/** this method checks for relevant intervals for energetic reasoning */
918static
919SCIP_RETCODE computeRelevantEnergyIntervals(
920 SCIP* scip, /**< SCIP data structure */
921 int nvars, /**< number of start time variables (activities) */
922 SCIP_VAR** vars, /**< array of start time variables */
923 int* durations, /**< array of durations */
924 int* demands, /**< array of demands */
925 int capacity, /**< cumulative capacity */
926 int hmin, /**< left bound of time axis to be considered (including hmin) */
927 int hmax, /**< right bound of time axis to be considered (not including hmax) */
928 int** timepoints, /**< array to store relevant points in time */
929 SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
930 int* ntimepoints, /**< pointer to store the number of timepoints */
931 int* maxdemand, /**< pointer to store maximum over all demands */
932 SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
933 )
934{
935 int* starttimes; /* stores when each job is starting */
936 int* endtimes; /* stores when each job ends */
937 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
938 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
939
940 SCIP_Real totaldemand;
941 int curtime; /* point in time which we are just checking */
942 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
943
944 int j;
945
946 assert( scip != NULL );
947 assert(durations != NULL);
948 assert(demands != NULL);
949 assert(capacity >= 0);
950
951 /* if no activities are associated with this cumulative then this constraint is redundant */
952 if( nvars == 0 )
953 return SCIP_OKAY;
954
955 assert(vars != NULL);
956
957 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
959 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
960 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
961
962 /* create event point arrays */
963 createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
964
965 endindex = 0;
966 totaldemand = 0.0;
967
968 *ntimepoints = 0;
969 (*timepoints)[0] = starttimes[0];
970 (*cumulativedemands)[0] = 0;
971 *maxdemand = 0;
972
973 /* check each startpoint of a job whether the capacity is kept or not */
974 for( j = 0; j < nvars; ++j )
975 {
976 int lct;
977 int idx;
978
979 curtime = starttimes[j];
980
981 if( curtime >= hmax )
982 break;
983
984 /* free all capacity usages of jobs the are no longer running */
985 while( endindex < nvars && endtimes[endindex] <= curtime )
986 {
987 int est;
988
989 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
990 {
991 (*ntimepoints)++;
992 (*timepoints)[*ntimepoints] = endtimes[endindex];
993 (*cumulativedemands)[*ntimepoints] = 0;
994 }
995
996 idx = endindices[endindex];
998 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
999 endindex++;
1000
1001 (*cumulativedemands)[*ntimepoints] = totaldemand;
1002 }
1003
1004 idx = startindices[j];
1005 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
1006 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
1007
1008 if( (*timepoints)[*ntimepoints] < curtime )
1009 {
1010 (*ntimepoints)++;
1011 (*timepoints)[*ntimepoints] = curtime;
1012 (*cumulativedemands)[*ntimepoints] = 0;
1013 }
1014
1015 (*cumulativedemands)[*ntimepoints] = totaldemand;
1016
1017 /* add the relative capacity requirements for all job which start at the curtime */
1018 while( j+1 < nvars && starttimes[j+1] == curtime )
1019 {
1020 ++j;
1021 idx = startindices[j];
1022 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
1023 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
1024
1025 (*cumulativedemands)[*ntimepoints] = totaldemand;
1026 }
1027 } /*lint --e{850}*/
1028
1029 /* free all capacity usages of jobs that are no longer running */
1030 while( endindex < nvars/* && endtimes[endindex] < hmax*/)
1031 {
1032 int est;
1033 int idx;
1034
1035 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
1036 {
1037 (*ntimepoints)++;
1038 (*timepoints)[*ntimepoints] = endtimes[endindex];
1039 (*cumulativedemands)[*ntimepoints] = 0;
1040 }
1041
1042 idx = endindices[endindex];
1044 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
1045 (*cumulativedemands)[*ntimepoints] = totaldemand;
1046
1047 ++endindex;
1048 }
1049
1050 (*ntimepoints)++;
1051 /* compute minimum free capacity */
1052 (*minfreecapacity) = INT_MAX;
1053 for( j = 0; j < *ntimepoints; ++j )
1054 {
1055 if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1056 *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1057 }
1058
1059 /* free buffer arrays */
1060 SCIPfreeBufferArray(scip, &endindices);
1061 SCIPfreeBufferArray(scip, &startindices);
1062 SCIPfreeBufferArray(scip, &endtimes);
1063 SCIPfreeBufferArray(scip, &starttimes);
1064
1065 return SCIP_OKAY;
1066}
1067
1068/** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1069static
1070SCIP_RETCODE evaluateCumulativeness(
1071 SCIP* scip, /**< pointer to scip */
1072 SCIP_CONS* cons /**< cumulative constraint */
1073 )
1074{
1075 SCIP_CONSDATA* consdata;
1076 int nvars;
1077 int v;
1078 int capacity;
1079
1080 /* output values: */
1081 SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1082 SCIP_Real cumfactor1;
1083 SCIP_Real resstrength1; /* overall strength */
1084 SCIP_Real resstrength2; /* timepoint wise maximum */
1085
1086 /* helpful variables: */
1087 SCIP_Real globalpeak;
1088 SCIP_Real globalmaxdemand;
1089
1090 /* get constraint data structure */
1091 consdata = SCIPconsGetData(cons);
1092 assert(consdata != NULL);
1093
1094 nvars = consdata->nvars;
1095 capacity = consdata->capacity;
1096 globalpeak = 0.0;
1097 globalmaxdemand = 0.0;
1098
1099 disjfactor2 = 0.0;
1100 cumfactor1 = 0.0;
1101 resstrength2 = 0.0;
1102
1103 /* check each starting time (==each job, but inefficient) */
1104 for( v = 0; v < nvars; ++v )
1105 {
1106 SCIP_Real peak;
1107 SCIP_Real maxdemand;
1108 SCIP_Real deltademand;
1109 int ndemands;
1110 int nlarge;
1111
1112 int timepoint;
1113 int j;
1114 timepoint = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1115 peak = consdata->demands[v];
1116 ndemands = 1;
1117 maxdemand = 0;
1118 nlarge = 0;
1119
1120 if( consdata->demands[v] > capacity / 3 )
1121 nlarge++;
1122
1123 for( j = 0; j < nvars; ++j )
1124 {
1125 int lb;
1126
1127 if( j == v )
1128 continue;
1129
1130 maxdemand = 0.0;
1131 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1132
1133 if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1134 {
1135 peak += consdata->demands[j];
1136 ndemands++;
1137
1138 if( consdata->demands[j] > consdata->capacity / 3 )
1139 nlarge++;
1140 }
1141 }
1142
1143 deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1144 globalpeak = MAX(globalpeak, peak);
1145 globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1146
1147 if( peak > capacity )
1148 {
1149 disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1150 cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1151 resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1152 }
1153 }
1154
1155 resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1156
1157 consdata->maxpeak = boundedConvertRealToInt(scip, globalpeak);
1158 consdata->disjfactor2 = disjfactor2;
1159 consdata->cumfactor1 = cumfactor1;
1160 consdata->resstrength2 = resstrength2;
1161 consdata->resstrength1 = resstrength1;
1162
1163 /* get estimated res strength */
1164 {
1165 int* timepoints;
1166 SCIP_Real* estimateddemands;
1167 int ntimepoints;
1168 int maxdemand;
1169 SCIP_Real minfreecapacity;
1170
1171 SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1172 SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1173
1174 ntimepoints = 0;
1175 minfreecapacity = INT_MAX;
1176
1177 SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1178 consdata->durations, consdata->demands,
1179 capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1180 &ntimepoints, &maxdemand, &minfreecapacity) );
1181
1182 /* free buffer arrays */
1183 SCIPfreeBufferArray(scip, &estimateddemands);
1184 SCIPfreeBufferArray(scip, &timepoints);
1185
1186 consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1187 }
1188
1189 SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1190 SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1191 consdata->estimatedstrength);
1192
1193 return SCIP_OKAY;
1194}
1195#endif
1196
1197/** gets the active variables together with the constant */
1198static
1200 SCIP* scip, /**< SCIP data structure */
1201 SCIP_VAR** var, /**< pointer to store the active variable */
1202 int* scalar, /**< pointer to store the scalar */
1203 int* constant /**< pointer to store the constant */
1204 )
1205{
1206 if( !SCIPvarIsActive(*var) )
1207 {
1208 SCIP_Real realscalar;
1209 SCIP_Real realconstant;
1210
1211 realscalar = 1.0;
1212 realconstant = 0.0;
1213
1215
1216 /* transform variable to active variable */
1217 SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1218 assert(!SCIPisZero(scip, realscalar));
1220
1221 if( realconstant < 0.0 )
1222 (*constant) = -boundedConvertRealToInt(scip, -realconstant);
1223 else
1224 (*constant) = boundedConvertRealToInt(scip, realconstant);
1225
1226 if( realscalar < 0.0 )
1227 (*scalar) = -boundedConvertRealToInt(scip, -realscalar);
1228 else
1229 (*scalar) = boundedConvertRealToInt(scip, realscalar);
1230 }
1231 else
1232 {
1233 (*scalar) = 1;
1234 (*constant) = 0;
1235 }
1236
1237 assert(*scalar != 0);
1238
1239 return SCIP_OKAY;
1240}
1241
1242/** computes the total energy of all jobs */
1243static
1245 int* durations, /**< array of job durations */
1246 int* demands, /**< array of job demands */
1247 int njobs /**< number of jobs */
1248 )
1249{
1250 SCIP_Longint energy;
1251 int j;
1252
1253 energy = 0;
1254
1255 for( j = 0; j < njobs; ++j )
1256 energy += (SCIP_Longint) durations[j] * demands[j];
1257
1258 return energy;
1259}
1260
1261/**@} */
1262
1263/**@name Default method to solve a cumulative condition
1264 *
1265 * @{
1266 */
1267
1268/** setup and solve subscip to solve single cumulative condition */
1269static
1271 SCIP* subscip, /**< subscip data structure */
1272 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1273 int* durations, /**< array of durations */
1274 int* demands, /**< array of demands */
1275 int njobs, /**< number of jobs (activities) */
1276 int capacity, /**< cumulative capacity */
1277 int hmin, /**< left bound of time axis to be considered (including hmin) */
1278 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1279 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1280 SCIP_Real timelimit, /**< time limit for solving in seconds */
1281 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1282 SCIP_Real* ests, /**< array of earliest start times for each job */
1283 SCIP_Real* lsts, /**< array of latest start times for each job */
1284 SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1285 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1286 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1287 SCIP_Bool* error /**< pointer to store if an error occurred */
1288 )
1289{
1290 SCIP_VAR** subvars;
1291 SCIP_CONS* cons;
1292
1293 char name[SCIP_MAXSTRLEN];
1294 int v;
1295 SCIP_RETCODE retcode;
1296
1297 assert(subscip != NULL);
1298
1299 /* copy all plugins */
1301
1302 /* create the subproblem */
1303 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1304
1305 SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1306
1307 /* create for each job a start time variable */
1308 for( v = 0; v < njobs; ++v )
1309 {
1311
1312 /* construct variable name */
1313 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1314
1315 if( objvals == NULL )
1316 objval = 0.0;
1317 else
1318 objval = objvals[v];
1319
1320 SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1321 SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1322 }
1323
1324 /* create cumulative constraint */
1325 SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1326 njobs, subvars, durations, demands, capacity) );
1327
1328 /* set effective horizon */
1329 SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1330 SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1331
1332 /* add cumulative constraint */
1333 SCIP_CALL( SCIPaddCons(subscip, cons) );
1334 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1335
1336 /* set CP solver settings
1337 *
1338 * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1339 * time limit.
1340 */
1342
1343 /* do not abort subproblem on CTRL-C */
1344 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1345
1346 /* disable output to console */
1347 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1348
1349 /* set limits for the subproblem */
1350 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1351 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1352 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1353
1354 /* forbid recursive call of heuristics and separators solving subMIPs */
1355 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1356
1357 /* solve single cumulative constraint by branch and bound */
1358 retcode = SCIPsolve(subscip);
1359
1360 if( retcode != SCIP_OKAY )
1361 (*error) = TRUE;
1362 else
1363 {
1364 SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1365
1366 /* evaluated solution status */
1367 switch( SCIPgetStatus(subscip) )
1368 {
1371 (*infeasible) = TRUE;
1372 (*solved) = TRUE;
1373 break;
1375 (*unbounded) = TRUE;
1376 (*solved) = TRUE;
1377 break;
1379 {
1380 SCIP_SOL* sol;
1381 SCIP_Real solval;
1382
1383 sol = SCIPgetBestSol(subscip);
1384 assert(sol != NULL);
1385
1386 for( v = 0; v < njobs; ++v )
1387 {
1388 solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1389
1390 ests[v] = solval;
1391 lsts[v] = solval;
1392 }
1393 (*solved) = TRUE;
1394 break;
1395 }
1402 /* transfer the global bound changes */
1403 for( v = 0; v < njobs; ++v )
1404 {
1405 ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1406 lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1407 }
1408 (*solved) = FALSE;
1409 break;
1410
1419 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1420 return SCIP_INVALIDDATA;
1421 }
1422 }
1423
1424 /* release all variables */
1425 for( v = 0; v < njobs; ++v )
1426 {
1427 SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1428 }
1429
1430 SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1431
1432 return SCIP_OKAY;
1433}
1434
1435/** solve single cumulative condition using SCIP and a single cumulative constraint */
1436static
1437SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1438{
1439 SCIP* subscip;
1440
1441 SCIP_RETCODE retcode;
1442
1443 assert(njobs > 0);
1444
1445 (*solved) = FALSE;
1446 (*infeasible) = FALSE;
1447 (*unbounded) = FALSE;
1448 (*error) = FALSE;
1449
1450 SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1451
1452 /* initialize the sub-problem */
1453 SCIP_CALL( SCIPcreate(&subscip) );
1454
1455 /* create and solve the subproblem. catch possible errors */
1456 retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1457 njobs, capacity, hmin, hmax,
1458 maxnodes, timelimit, memorylimit,
1459 ests, lsts,
1460 infeasible, unbounded, solved, error);
1461
1462 /* free the subscip in any case */
1463 SCIP_CALL( SCIPfree(&subscip) );
1464
1465 SCIP_CALL( retcode );
1466
1467 return SCIP_OKAY;
1468}
1469
1470#ifdef SCIP_DISABLED_CODE
1471/* The following code should work, but is currently not used. */
1472
1473/** solve single cumulative condition using SCIP and the time indexed formulation */
1474static
1475SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1476{
1477 SCIP* subscip;
1478 SCIP_VAR*** binvars;
1479 SCIP_RETCODE retcode;
1480 char name[SCIP_MAXSTRLEN];
1481 int minest;
1482 int maxlct;
1483 int t;
1484 int v;
1485
1486 assert(njobs > 0);
1487
1488 (*solved) = FALSE;
1489 (*infeasible) = FALSE;
1490 (*unbounded) = FALSE;
1491 (*error) = FALSE;
1492
1493 SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1494
1495 /* initialize the sub-problem */
1496 SCIP_CALL( SCIPcreate(&subscip) );
1497
1498 /* copy all plugins */
1500
1501 /* create the subproblem */
1502 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1503
1504 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1505
1506 minest = INT_MAX;
1507 maxlct = INT_MIN;
1508
1509 /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1510 * partitioning constrain which forces that job starts
1511 */
1512 for( v = 0; v < njobs; ++v )
1513 {
1514 SCIP_CONS* cons;
1516 int timeinterval;
1517 int est;
1518 int lst;
1519
1520 if( objvals == NULL )
1521 objval = 0.0;
1522 else
1523 objval = objvals[v];
1524
1525 est = ests[v];
1526 lst = lsts[v];
1527
1528 /* compute number of possible start points */
1529 timeinterval = lst - est + 1;
1530 assert(timeinterval > 0);
1531
1532 /* compute the smallest earliest start time and largest latest completion time */
1533 minest = MIN(minest, est);
1534 maxlct = MAX(maxlct, lst + durations[v]);
1535
1536 /* construct constraint name */
1537 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1538
1539 SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1540
1541 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1542
1543 for( t = 0; t < timeinterval; ++t )
1544 {
1545 SCIP_VAR* binvar;
1546
1547 /* construct varibale name */
1548 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1549
1550 SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1551 SCIP_CALL( SCIPaddVar(subscip, binvar) );
1552
1553 /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1554 SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1555
1556 binvars[v][t] = binvar;
1557 }
1558
1559 /* add and release the set partitioning constraint */
1560 SCIP_CALL( SCIPaddCons(subscip, cons) );
1561 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1562 }
1563
1564 /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1565 hmin = MAX(hmin, minest);
1566 hmax = MIN(hmax, maxlct);
1567 assert(hmin > INT_MIN);
1568 assert(hmax < INT_MAX);
1569 assert(hmin < hmax);
1570
1571 /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1572 for( t = hmin; t < hmax; ++t )
1573 {
1574 SCIP_CONS* cons;
1575
1576 /* construct constraint name */
1577 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1578
1579 /* create an empty knapsack constraint */
1580 SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1581
1582 /* add all jobs which potentially can be processed at that time point */
1583 for( v = 0; v < njobs; ++v )
1584 {
1585 int duration;
1586 int demand;
1587 int start;
1588 int end;
1589 int est;
1590 int lst;
1591 int k;
1592
1593 est = ests[v];
1594 lst = lsts[v] ;
1595
1596 duration = durations[v];
1597 assert(duration > 0);
1598
1599 /* check if the varibale is processed potentially at time point t */
1600 if( t < est || t >= lst + duration )
1601 continue;
1602
1603 demand = demands[v];
1604 assert(demand >= 0);
1605
1606 start = MAX(t - duration + 1, est);
1607 end = MIN(t, lst);
1608
1609 assert(start <= end);
1610
1611 for( k = start; k <= end; ++k )
1612 {
1613 assert(binvars[v][k] != NULL);
1614 SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1615 }
1616 }
1617
1618 /* add and release the knapsack constraint */
1619 SCIP_CALL( SCIPaddCons(subscip, cons) );
1620 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1621 }
1622
1623 /* do not abort subproblem on CTRL-C */
1624 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1625
1626 /* disable output to console */
1627 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1628
1629 /* set limits for the subproblem */
1630 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1631 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1632 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1633
1634 /* solve single cumulative constraint by branch and bound */
1635 retcode = SCIPsolve(subscip);
1636
1637 if( retcode != SCIP_OKAY )
1638 (*error) = TRUE;
1639 else
1640 {
1641 SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1642
1643 /* evaluated solution status */
1644 switch( SCIPgetStatus(subscip) )
1645 {
1648 (*infeasible) = TRUE;
1649 (*solved) = TRUE;
1650 break;
1652 (*unbounded) = TRUE;
1653 (*solved) = TRUE;
1654 break;
1656 {
1657 SCIP_SOL* sol;
1658
1659 sol = SCIPgetBestSol(subscip);
1660 assert(sol != NULL);
1661
1662 for( v = 0; v < njobs; ++v )
1663 {
1664 int timeinterval;
1665 int est;
1666 int lst;
1667
1668 est = ests[v];
1669 lst = lsts[v];
1670
1671 /* compute number of possible start points */
1672 timeinterval = lst - est + 1;
1673
1674 /* check which binary varibale is set to one */
1675 for( t = 0; t < timeinterval; ++t )
1676 {
1677 if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1678 {
1679 ests[v] = est + t;
1680 lsts[v] = est + t;
1681 break;
1682 }
1683 }
1684 }
1685
1686 (*solved) = TRUE;
1687 break;
1688 }
1694 /* transfer the global bound changes */
1695 for( v = 0; v < njobs; ++v )
1696 {
1697 int timeinterval;
1698 int est;
1699 int lst;
1700
1701 est = ests[v];
1702 lst = lsts[v];
1703
1704 /* compute number of possible start points */
1705 timeinterval = lst - est + 1;
1706
1707 /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1708 for( t = 0; t < timeinterval; ++t )
1709 {
1710 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1711 {
1712 ests[v] = est + t;
1713 break;
1714 }
1715 }
1716
1717 /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1718 for( t = timeinterval - 1; t >= 0; --t )
1719 {
1720 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1721 {
1722 lsts[v] = est + t;
1723 break;
1724 }
1725 }
1726 }
1727 (*solved) = FALSE;
1728 break;
1729
1735 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1736 return SCIP_INVALIDDATA;
1737 }
1738 }
1739
1740 /* release all variables */
1741 for( v = 0; v < njobs; ++v )
1742 {
1743 int timeinterval;
1744 int est;
1745 int lst;
1746
1747 est = ests[v];
1748 lst = lsts[v];
1749
1750 /* compute number of possible start points */
1751 timeinterval = lst - est + 1;
1752
1753 for( t = 0; t < timeinterval; ++t )
1754 {
1755 SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1756 }
1757 SCIPfreeBufferArray(subscip, &binvars[v]);
1758 }
1759
1760 SCIPfreeBufferArray(subscip, &binvars);
1761
1762 SCIP_CALL( SCIPfree(&subscip) );
1763
1764 return SCIP_OKAY;
1765}
1766#endif
1767
1768/**@} */
1769
1770/**@name Constraint handler data
1771 *
1772 * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1773 * handler.
1774 *
1775 * @{
1776 */
1777
1778/** creates constaint handler data for cumulative constraint handler */
1779static
1781 SCIP* scip, /**< SCIP data structure */
1782 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1783 SCIP_EVENTHDLR* eventhdlr /**< event handler */
1784 )
1785{
1786 /* create precedence constraint handler data */
1787 assert(scip != NULL);
1788 assert(conshdlrdata != NULL);
1789 assert(eventhdlr != NULL);
1790
1791 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1792
1793 /* set event handler for checking if bounds of start time variables are tighten */
1794 (*conshdlrdata)->eventhdlr = eventhdlr;
1795
1796 /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1797 (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1798
1799#ifdef SCIP_STATISTIC
1800 (*conshdlrdata)->nlbtimetable = 0;
1801 (*conshdlrdata)->nubtimetable = 0;
1802 (*conshdlrdata)->ncutofftimetable = 0;
1803 (*conshdlrdata)->nlbedgefinder = 0;
1804 (*conshdlrdata)->nubedgefinder = 0;
1805 (*conshdlrdata)->ncutoffedgefinder = 0;
1806 (*conshdlrdata)->ncutoffoverload = 0;
1807 (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1808
1809 (*conshdlrdata)->nirrelevantjobs = 0;
1810 (*conshdlrdata)->nalwaysruns = 0;
1811 (*conshdlrdata)->nremovedlocks = 0;
1812 (*conshdlrdata)->ndualfixs = 0;
1813 (*conshdlrdata)->ndecomps = 0;
1814 (*conshdlrdata)->ndualbranchs = 0;
1815 (*conshdlrdata)->nallconsdualfixs = 0;
1816 (*conshdlrdata)->naddedvarbounds = 0;
1817 (*conshdlrdata)->naddeddisjunctives = 0;
1818#endif
1819
1820 return SCIP_OKAY;
1821}
1822
1823/** frees constraint handler data for logic or constraint handler */
1824static
1826 SCIP* scip, /**< SCIP data structure */
1827 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1828 )
1829{
1830 assert(conshdlrdata != NULL);
1831 assert(*conshdlrdata != NULL);
1832
1833 SCIPfreeBlockMemory(scip, conshdlrdata);
1834}
1835
1836/**@} */
1837
1838
1839/**@name Constraint data methods
1840 *
1841 * @{
1842 */
1843
1844/** catches bound change events for all variables in transformed cumulative constraint */
1845static
1847 SCIP* scip, /**< SCIP data structure */
1848 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1849 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1850 )
1851{
1852 int v;
1853
1854 assert(scip != NULL);
1855 assert(consdata != NULL);
1856 assert(eventhdlr != NULL);
1857
1858 /* catch event for every single variable */
1859 for( v = 0; v < consdata->nvars; ++v )
1860 {
1861 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1862 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1863 }
1864
1865 return SCIP_OKAY;
1866}
1867
1868/** drops events for variable at given position */
1869static
1871 SCIP* scip, /**< SCIP data structure */
1872 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1873 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1874 int pos /**< array position of variable to catch bound change events for */
1875 )
1876{
1877 assert(scip != NULL);
1878 assert(consdata != NULL);
1879 assert(eventhdlr != NULL);
1880 assert(0 <= pos && pos < consdata->nvars);
1881 assert(consdata->vars[pos] != NULL);
1882
1883 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1884 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1885
1886 return SCIP_OKAY;
1887}
1888
1889/** drops bound change events for all variables in transformed linear constraint */
1890static
1892 SCIP* scip, /**< SCIP data structure */
1893 SCIP_CONSDATA* consdata, /**< linear constraint data */
1894 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1895 )
1896{
1897 int v;
1898
1899 assert(scip != NULL);
1900 assert(consdata != NULL);
1901
1902 /* drop event of every single variable */
1903 for( v = 0; v < consdata->nvars; ++v )
1904 {
1905 SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1906 }
1907
1908 return SCIP_OKAY;
1909}
1910
1911/** initialize variable lock data structure */
1912static
1914 SCIP_CONSDATA* consdata, /**< constraint data */
1915 SCIP_Bool locked /**< should the variable be locked? */
1916 )
1917{
1918 int nvars;
1919 int v;
1920
1921 nvars = consdata->nvars;
1922
1923 /* initialize locking arrays */
1924 for( v = 0; v < nvars; ++v )
1925 {
1926 consdata->downlocks[v] = locked;
1927 consdata->uplocks[v] = locked;
1928 }
1929}
1930
1931/** creates constraint data of cumulative constraint */
1932static
1934 SCIP* scip, /**< SCIP data structure */
1935 SCIP_CONSDATA** consdata, /**< pointer to consdata */
1936 SCIP_VAR** vars, /**< array of integer variables */
1937 SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1938 int* durations, /**< array containing corresponding durations */
1939 int* demands, /**< array containing corresponding demands */
1940 int nvars, /**< number of variables */
1941 int capacity, /**< available cumulative capacity */
1942 int hmin, /**< left bound of time axis to be considered (including hmin) */
1943 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1944 SCIP_Bool check /**< is the corresponding constraint a check constraint */
1945 )
1946{
1947 int v;
1948
1949 assert(scip != NULL);
1950 assert(consdata != NULL);
1951 assert(vars != NULL || nvars > 0);
1952 assert(demands != NULL);
1953 assert(durations != NULL);
1954 assert(capacity >= 0);
1955 assert(hmin >= 0);
1956 assert(hmin < hmax);
1957
1958 /* create constraint data */
1959 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1960
1961 (*consdata)->hmin = hmin;
1962 (*consdata)->hmax = hmax;
1963
1964 (*consdata)->capacity = capacity;
1965 (*consdata)->demandrows = NULL;
1966 (*consdata)->demandrowssize = 0;
1967 (*consdata)->ndemandrows = 0;
1968 (*consdata)->scoverrows = NULL;
1969 (*consdata)->nscoverrows = 0;
1970 (*consdata)->scoverrowssize = 0;
1971 (*consdata)->bcoverrows = NULL;
1972 (*consdata)->nbcoverrows = 0;
1973 (*consdata)->bcoverrowssize = 0;
1974 (*consdata)->nvars = nvars;
1975 (*consdata)->varssize = nvars;
1976 (*consdata)->signature = 0;
1977 (*consdata)->validsignature = FALSE;
1978 (*consdata)->normalized = FALSE;
1979 (*consdata)->covercuts = FALSE;
1980 (*consdata)->propagated = FALSE;
1981 (*consdata)->varbounds = FALSE;
1982 (*consdata)->triedsolving = FALSE;
1983
1984 if( nvars > 0 )
1985 {
1986 assert(vars != NULL); /* for flexelint */
1987
1988 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1989 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1990 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1991 (*consdata)->linkingconss = NULL;
1992
1993 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1994 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1995
1996 /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
1997 initializeLocks(*consdata, check);
1998
1999 if( linkingconss != NULL )
2000 {
2001 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
2002 }
2003
2004 /* transform variables, if they are not yet transformed */
2005 if( SCIPisTransformed(scip) )
2006 {
2007 SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
2008
2009 /* get transformed variables and do NOT captures these */
2010 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
2011
2012 /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
2013 * been multi-aggregated
2014 */
2015 for( v = 0; v < nvars; ++v )
2016 {
2017 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
2018 }
2019
2020 if( linkingconss != NULL )
2021 {
2022 /* get transformed constraints and captures these */
2023 SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
2024
2025 for( v = 0; v < nvars; ++v )
2026 assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
2027 }
2028 }
2029
2030#ifndef NDEBUG
2031 /* only binary and integer variables can be used in cumulative constraints
2032 * for fractional variable values, the constraint cannot be checked
2033 */
2034 for( v = 0; v < (*consdata)->nvars; ++v )
2035 assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
2036#endif
2037 }
2038 else
2039 {
2040 (*consdata)->vars = NULL;
2041 (*consdata)->downlocks = NULL;
2042 (*consdata)->uplocks = NULL;
2043 (*consdata)->demands = NULL;
2044 (*consdata)->durations = NULL;
2045 (*consdata)->linkingconss = NULL;
2046 }
2047
2048 /* initialize values for running propagation algorithms efficiently */
2049 (*consdata)->resstrength1 = -1.0;
2050 (*consdata)->resstrength2 = -1.0;
2051 (*consdata)->cumfactor1 = -1.0;
2052 (*consdata)->disjfactor1 = -1.0;
2053 (*consdata)->disjfactor2 = -1.0;
2054 (*consdata)->estimatedstrength = -1.0;
2055
2056 SCIPstatistic( (*consdata)->maxpeak = -1 );
2057
2058 return SCIP_OKAY;
2059}
2060
2061/** releases LP rows of constraint data and frees rows array */
2062static
2064 SCIP* scip, /**< SCIP data structure */
2065 SCIP_CONSDATA** consdata /**< constraint data */
2066 )
2067{
2068 int r;
2069
2070 assert(consdata != NULL);
2071 assert(*consdata != NULL);
2072
2073 for( r = 0; r < (*consdata)->ndemandrows; ++r )
2074 {
2075 assert((*consdata)->demandrows[r] != NULL);
2076 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2077 }
2078
2079 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2080
2081 (*consdata)->ndemandrows = 0;
2082 (*consdata)->demandrowssize = 0;
2083
2084 /* free rows of cover cuts */
2085 for( r = 0; r < (*consdata)->nscoverrows; ++r )
2086 {
2087 assert((*consdata)->scoverrows[r] != NULL);
2088 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2089 }
2090
2091 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2092
2093 (*consdata)->nscoverrows = 0;
2094 (*consdata)->scoverrowssize = 0;
2095
2096 for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2097 {
2098 assert((*consdata)->bcoverrows[r] != NULL);
2099 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2100 }
2101
2102 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2103
2104 (*consdata)->nbcoverrows = 0;
2105 (*consdata)->bcoverrowssize = 0;
2106
2107 (*consdata)->covercuts = FALSE;
2108
2109 return SCIP_OKAY;
2110}
2111
2112/** frees a cumulative constraint data */
2113static
2115 SCIP* scip, /**< SCIP data structure */
2116 SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2117 )
2118{
2119 int varssize;
2120 int nvars;
2121
2122 assert(consdata != NULL);
2123 assert(*consdata != NULL);
2124
2125 nvars = (*consdata)->nvars;
2126 varssize = (*consdata)->varssize;
2127
2128 if( varssize > 0 )
2129 {
2130 int v;
2131
2132 /* release and free the rows */
2133 SCIP_CALL( consdataFreeRows(scip, consdata) );
2134
2135 /* release the linking constraints if they were generated */
2136 if( (*consdata)->linkingconss != NULL )
2137 {
2138 for( v = nvars-1; v >= 0; --v )
2139 {
2140 assert((*consdata)->linkingconss[v] != NULL );
2141 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2142 }
2143
2144 SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2145 }
2146
2147 /* free arrays */
2148 SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2149 SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2150 SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2151 SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2152 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2153 }
2154
2155 /* free memory */
2156 SCIPfreeBlockMemory(scip, consdata);
2157
2158 return SCIP_OKAY;
2159}
2160
2161/** prints cumulative constraint to file stream */
2162static
2164 SCIP* scip, /**< SCIP data structure */
2165 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2166 FILE* file /**< output file (or NULL for standard output) */
2167 )
2168{
2169 int v;
2170
2171 assert(consdata != NULL);
2172
2173 /* print coefficients */
2174 SCIPinfoMessage( scip, file, "cumulative(");
2175
2176 for( v = 0; v < consdata->nvars; ++v )
2177 {
2178 assert(consdata->vars[v] != NULL);
2179 if( v > 0 )
2180 SCIPinfoMessage(scip, file, ", ");
2181 SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2182 SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2183 consdata->durations[v], consdata->demands[v]);
2184 }
2185 SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2186}
2187
2188/** deletes coefficient at given position from constraint data */
2189static
2191 SCIP* scip, /**< SCIP data structure */
2192 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2193 SCIP_CONS* cons, /**< knapsack constraint */
2194 int pos /**< position of coefficient to delete */
2195 )
2196{
2197 SCIP_CONSHDLR* conshdlr;
2198 SCIP_CONSHDLRDATA* conshdlrdata;
2199
2200 assert(scip != NULL);
2201 assert(consdata != NULL);
2202 assert(cons != NULL);
2205
2206 SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2207 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2208
2209 /* remove the rounding locks for the deleted variable */
2210 SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2211
2212 consdata->downlocks[pos] = FALSE;
2213 consdata->uplocks[pos] = FALSE;
2214
2215 if( consdata->linkingconss != NULL )
2216 {
2217 SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2218 }
2219
2220 /* get event handler */
2221 conshdlr = SCIPconsGetHdlr(cons);
2222 assert(conshdlr != NULL);
2223 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2224 assert(conshdlrdata != NULL);
2225 assert(conshdlrdata->eventhdlr != NULL);
2226
2227 /* drop events */
2228 SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2229
2230 SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2231 SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2232
2233 /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2234 * position
2235 */
2236 if( pos != consdata->nvars - 1 )
2237 {
2238 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2239 consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2240 consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2241 consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2242 consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2243
2244 if( consdata->linkingconss != NULL )
2245 {
2246 consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2247 }
2248 }
2249
2250 consdata->nvars--;
2251 consdata->validsignature = FALSE;
2252 consdata->normalized = FALSE;
2253
2254 return SCIP_OKAY;
2255}
2256
2257/** collect linking constraints for each integer variable */
2258static
2260 SCIP* scip, /**< SCIP data structure */
2261 SCIP_CONSDATA* consdata /**< pointer to consdata */
2262 )
2263{
2264 int nvars;
2265 int v;
2266
2267 assert(scip != NULL);
2268 assert(consdata != NULL);
2269
2270 nvars = consdata->nvars;
2271 assert(nvars > 0);
2272 assert(consdata->linkingconss == NULL);
2273
2274 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2275
2276 for( v = 0; v < nvars; ++v )
2277 {
2278 SCIP_CONS* cons;
2279 SCIP_VAR* var;
2280
2281 var = consdata->vars[v];
2282 assert(var != NULL);
2283
2284 SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2285
2286 /* create linking constraint if it does not exist yet */
2288 {
2289 char name[SCIP_MAXSTRLEN];
2290
2291 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2292
2293 /* creates and captures an linking constraint */
2294 SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2295 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2296 SCIP_CALL( SCIPaddCons(scip, cons) );
2297 consdata->linkingconss[v] = cons;
2298 }
2299 else
2300 {
2301 consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2302 SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2303 }
2304
2306 assert(consdata->linkingconss[v] != NULL);
2307 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2308
2309 SCIP_STRINGEQ( SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking", SCIP_INVALIDCALL );
2310 }
2311
2312 return SCIP_OKAY;
2313}
2314
2315/**@} */
2316
2317
2318/**@name Check methods
2319 *
2320 * @{
2321 */
2322
2323/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2324 * given solution is satisfied
2325 */
2326static
2328 SCIP* scip, /**< SCIP data structure */
2329 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2330 int nvars, /**< number of variables (jobs) */
2331 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2332 int* durations, /**< array containing corresponding durations */
2333 int* demands, /**< array containing corresponding demands */
2334 int capacity, /**< available cumulative capacity */
2335 int hmin, /**< left bound of time axis to be considered (including hmin) */
2336 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2337 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2338 SCIP_CONS* cons, /**< constraint which is checked */
2339 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2340 )
2341{
2342 int* startsolvalues; /* stores when each job is starting */
2343 int* endsolvalues; /* stores when each job ends */
2344 int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2345 int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2346
2347 int freecapacity;
2348 int curtime; /* point in time which we are just checking */
2349 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2350 int j;
2351
2352 SCIP_Real absviol;
2353 SCIP_Real relviol;
2354
2355 assert(scip != NULL);
2356 assert(violated != NULL);
2357
2358 (*violated) = FALSE;
2359
2360 if( nvars == 0 )
2361 return SCIP_OKAY;
2362
2363 assert(vars != NULL);
2364 assert(demands != NULL);
2365 assert(durations != NULL);
2366
2367 /* compute time points where we have to check whether capacity constraint is infeasible or not */
2368 SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2369 SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2370 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2371 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2372
2373 /* assign variables, start and endpoints to arrays */
2374 for ( j = 0; j < nvars; ++j )
2375 {
2376 int solvalue;
2377
2378 /* the constraint of the cumulative constraint handler should be called after the integrality check */
2380
2382
2383 /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2384 * jobs which start before hmin to hmin
2385 */
2386 startsolvalues[j] = MAX(solvalue, hmin);
2387 startindices[j] = j;
2388
2389 endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2390 endindices[j] = j;
2391 }
2392
2393 /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2394 * corresponding indices in the same way)
2395 */
2396 SCIPsortIntInt(startsolvalues, startindices, nvars);
2397 SCIPsortIntInt(endsolvalues, endindices, nvars);
2398
2399 endindex = 0;
2400 freecapacity = capacity;
2401 absviol = 0.0;
2402 relviol = 0.0;
2403
2404 /* check each start point of a job whether the capacity is kept or not */
2405 for( j = 0; j < nvars; ++j )
2406 {
2407 /* only check intervals [hmin,hmax) */
2408 curtime = startsolvalues[j];
2409
2410 if( curtime >= hmax )
2411 break;
2412
2413 /* subtract all capacity needed up to this point */
2414 freecapacity -= demands[startindices[j]];
2415 while( j+1 < nvars && startsolvalues[j+1] == curtime )
2416 {
2417 j++;
2418 freecapacity -= demands[startindices[j]];
2419 }
2420
2421 /* free all capacity usages of jobs that are no longer running */
2422 while( endindex < nvars && curtime >= endsolvalues[endindex] )
2423 {
2424 freecapacity += demands[endindices[endindex]];
2425 ++endindex;
2426 }
2427 assert(freecapacity <= capacity);
2428
2429 /* update absolute and relative violation */
2430 if( absviol < (SCIP_Real) (-freecapacity) )
2431 {
2432 absviol = -freecapacity;
2433 relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2434 }
2435
2436 /* check freecapacity to be smaller than zero */
2437 if( freecapacity < 0 && curtime >= hmin )
2438 {
2439 SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2440 (*violated) = TRUE;
2441
2442 if( printreason )
2443 {
2444 int i;
2445
2446 /* first state the violated constraints */
2447 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2448
2449 /* second state the reason */
2451 ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2452 curtime, capacity, capacity - freecapacity);
2453
2454 for( i = 0; i <= j; ++i )
2455 {
2456 if( startsolvalues[i] + durations[startindices[i]] > curtime )
2457 {
2458 SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2459 SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2460 demands[startindices[i]]);
2461 }
2462 }
2463 }
2464 break;
2465 }
2466 } /*lint --e{850}*/
2467
2468 /* update constraint violation in solution */
2469 if( sol != NULL )
2470 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2471
2472 /* free all buffer arrays */
2473 SCIPfreeBufferArray(scip, &endindices);
2474 SCIPfreeBufferArray(scip, &startindices);
2475 SCIPfreeBufferArray(scip, &endsolvalues);
2476 SCIPfreeBufferArray(scip, &startsolvalues);
2477
2478 return SCIP_OKAY;
2479}
2480
2481/** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2482 * least zero or not. If not (*violated) is set to TRUE
2483 */
2484static
2486 SCIP* scip, /**< SCIP data structure */
2487 SCIP_CONS* cons, /**< constraint to be checked */
2488 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2489 SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2490 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2491 )
2492{
2493 SCIP_CONSDATA* consdata;
2494
2495 assert(scip != NULL);
2496 assert(cons != NULL);
2497 assert(violated != NULL);
2498
2499 SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2500
2501 consdata = SCIPconsGetData(cons);
2502 assert(consdata != NULL);
2503
2504 /* check the cumulative condition */
2505 SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2506 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2507 violated, cons, printreason) );
2508
2509 return SCIP_OKAY;
2510}
2511
2512/**@} */
2513
2514/**@name Conflict analysis
2515 *
2516 * @{
2517 */
2518
2519/** resolves the propagation of the core time algorithm */
2520static
2522 SCIP* scip, /**< SCIP data structure */
2523 int nvars, /**< number of start time variables (activities) */
2524 SCIP_VAR** vars, /**< array of start time variables */
2525 int* durations, /**< array of durations */
2526 int* demands, /**< array of demands */
2527 int capacity, /**< cumulative capacity */
2528 int hmin, /**< left bound of time axis to be considered (including hmin) */
2529 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2530 SCIP_VAR* infervar, /**< inference variable */
2531 int inferdemand, /**< demand of the inference variable */
2532 int inferpeak, /**< time point which causes the propagation */
2533 int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2534 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2535 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2536 int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2537 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2538 )
2539{
2540 SCIP_VAR* var;
2541 SCIP_Bool* reported;
2542 int duration;
2543 int maxlst;
2544 int minect;
2545 int ect;
2546 int lst;
2547 int j;
2548
2550
2551 SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2552 SCIPvarGetName(infervar), inferdemand, inferpeak);
2553 assert(nvars > 0);
2554
2555 /* adjusted capacity */
2556 capacity -= inferdemand;
2557 maxlst = INT_MIN;
2558 minect = INT_MAX;
2559
2560 SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2561 BMSclearMemoryArray(reported, nvars);
2562
2563 /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2564 * inference peak and those where the current conflict bounds provide a core at the inference peak
2565 */
2566 for( j = 0; j < nvars && capacity >= 0; ++j )
2567 {
2568 var = vars[j];
2569 assert(var != NULL);
2570
2571 /* skip inference variable */
2572 if( var == infervar )
2573 continue;
2574
2575 duration = durations[j];
2576 assert(duration > 0);
2577
2578 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2583
2584 SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2586 SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2587
2590
2591 /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2592 * that job without adding it the explanation
2593 */
2594 if( inferpeak < ect && lst <= inferpeak )
2595 {
2596 capacity -= demands[j];
2597 reported[j] = TRUE;
2598
2599 maxlst = MAX(maxlst, lst);
2600 minect = MIN(minect, ect);
2601 assert(maxlst < minect);
2602
2603 if( explanation != NULL )
2604 explanation[j] = TRUE;
2605
2606 continue;
2607 }
2608
2609 /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2610 * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2611 * not part of the conflict yet we get the global bounds back.
2612 */
2615
2616 /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2617 * of that job without and collect the job as part of the explanation
2618 *
2619 * @note we do not need to reported that job to SCIP since the required bounds are already reported
2620 */
2621 if( inferpeak < ect && lst <= inferpeak )
2622 {
2623 capacity -= demands[j];
2624 reported[j] = TRUE;
2625
2626 maxlst = MAX(maxlst, lst);
2627 minect = MIN(minect, ect);
2628 assert(maxlst < minect);
2629
2630 if( explanation != NULL )
2631 explanation[j] = TRUE;
2632 }
2633 }
2634
2635 if( capacity >= 0 )
2636 {
2637 int* cands;
2638 int* canddemands;
2639 int ncands;
2640 int c;
2641
2643 SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2644 ncands = 0;
2645
2646 /* collect all cores of the variables which lay in the considered time window except the inference variable */
2647 for( j = 0; j < nvars; ++j )
2648 {
2649 var = vars[j];
2650 assert(var != NULL);
2651
2652 /* skip inference variable */
2653 if( var == infervar || reported[j] )
2654 continue;
2655
2656 duration = durations[j];
2657 assert(duration > 0);
2658
2659 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2664
2665 /* collect local core information */
2666 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2668
2669 SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2671 SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2672
2673 /* check if the inference peak is part of the core */
2674 if( inferpeak < ect && lst <= inferpeak )
2675 {
2676 cands[ncands] = j;
2677 canddemands[ncands] = demands[j];
2678 ncands++;
2679
2680 capacity -= demands[j];
2681 }
2682 }
2683
2684 /* sort candidates indices w.r.t. their demands */
2685 SCIPsortDownIntInt(canddemands, cands, ncands);
2686
2687 assert(capacity < 0);
2688 assert(ncands > 0);
2689
2690 /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2691 while( capacity + canddemands[ncands-1] < 0 )
2692 {
2693 ncands--;
2694 capacity += canddemands[ncands];
2695 assert(ncands > 0);
2696 }
2697
2698 /* compute the size (number of time steps) of the job cores */
2699 for( c = 0; c < ncands; ++c )
2700 {
2701 var = vars[cands[c]];
2702 assert(var != NULL);
2703
2704 duration = durations[cands[c]];
2705
2706 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2708
2709 maxlst = MAX(maxlst, lst);
2710 minect = MIN(minect, ect);
2711 assert(maxlst < minect);
2712 }
2713
2714 SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2715 assert(inferpeak >= maxlst);
2716 assert(inferpeak < minect);
2717
2718 /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2719 if( relaxedpeak < inferpeak )
2720 {
2721 inferpeak = MAX(maxlst, relaxedpeak);
2722 }
2723 else if( relaxedpeak > inferpeak )
2724 {
2725 inferpeak = MIN(minect-1, relaxedpeak);
2726 }
2727 assert(inferpeak >= hmin);
2728 assert(inferpeak < hmax);
2729 assert(inferpeak >= maxlst);
2730 assert(inferpeak < minect);
2731
2732 /* post all necessary bound changes */
2733 for( c = 0; c < ncands; ++c )
2734 {
2735 var = vars[cands[c]];
2736 assert(var != NULL);
2737
2738 if( usebdwidening )
2739 {
2740 duration = durations[cands[c]];
2741
2742 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2743 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2744 }
2745 else
2746 {
2747 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2748 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2749 }
2750
2751 if( explanation != NULL )
2752 explanation[cands[c]] = TRUE;
2753 }
2754
2755 SCIPfreeBufferArray(scip, &canddemands);
2756 SCIPfreeBufferArray(scip, &cands);
2757 }
2758
2759 SCIPfreeBufferArray(scip, &reported);
2760
2761 if( provedpeak != NULL )
2762 *provedpeak = inferpeak;
2763
2764 return SCIP_OKAY;
2765}
2766
2767/** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2768static
2770 int begin, /**< begin of the times interval */
2771 int end, /**< end of time interval */
2772 int est, /**< earliest start time */
2773 int lst, /**< latest start time */
2774 int duration /**< duration of the job */
2775 )
2776{
2777 int left;
2778 int right;
2779 int ect;
2780 int lct;
2781
2782 ect = est + duration;
2783 lct = lst + duration;
2784
2785 /* check if job runs completely within [begin,end) */
2786 if( lct <= end && est >= begin )
2787 return duration;
2788
2789 assert(lst <= end && ect >= begin);
2790
2791 left = ect - begin;
2792 assert(left > 0);
2793
2794 right = end - lst;
2795 assert(right > 0);
2796
2797 return MIN3(left, right, end - begin);
2798}
2799
2800/** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2801 * reason
2802 *
2803 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2804 */
2805static
2807 SCIP* scip, /**< SCIP data structure */
2808 int nvars, /**< number of start time variables (activities) */
2809 SCIP_VAR** vars, /**< array of start time variables */
2810 int* durations, /**< array of durations */
2811 int* demands, /**< array of demands */
2812 int capacity, /**< capacity of the cumulative condition */
2813 int begin, /**< begin of the time window */
2814 int end, /**< end of the time window */
2815 SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2816 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2817 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2818 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2819 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2820 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2821 )
2822{
2823 int* locenergies;
2824 int* overlaps;
2825 int* idxs;
2826
2827 SCIP_Longint requiredenergy;
2828 int v;
2829
2830 SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2831 SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2833
2834 /* energy which needs be explained */
2835 requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2836
2837 SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2838
2839 /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2840 * takes
2841 */
2842 for( v = 0; v < nvars; ++v )
2843 {
2844 SCIP_VAR* var;
2845 int glbenergy;
2846 int duration;
2847 int demand;
2848 int est;
2849 int lst;
2850
2851 var = vars[v];
2852 assert(var != NULL);
2853
2854 locenergies[v] = 0;
2855 overlaps[v] = 0;
2856 idxs[v] = v;
2857
2858 demand = demands[v];
2859 assert(demand > 0);
2860
2861 duration = durations[v];
2862 assert(duration > 0);
2863
2864 /* check if the variable equals the inference variable (the one which was propagated) */
2865 if( infervar == var )
2866 {
2867 int overlap;
2868 int right;
2869 int left;
2870
2871 assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2872
2873 SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2875 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2876
2877 /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2878 * which is necessary from the inference variable
2879 */
2880 if( boundtype == SCIP_BOUNDTYPE_UPPER )
2881 {
2882 int lct;
2883
2884 /* get the latest start time of the infer start time variable before the propagation took place */
2886
2887 /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2888 * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2889 * scheduled w.r.t. its latest start time
2890 */
2891 assert(lst < end);
2892
2893 /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2894 * interval (before the propagation)
2895 */
2896 right = MIN3(end - lst, end - begin, duration);
2897
2898 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2899 assert(right > 0);
2900
2901 lct = boundedConvertRealToInt(scip, relaxedbd) + duration;
2902 assert(begin <= lct);
2903 assert(bdchgidx == NULL ||
2905
2906 /* compute the overlap of the job after the propagation but considering the relaxed bound */
2907 left = MIN(lct - begin + 1, end - begin);
2908 assert(left > 0);
2909
2910 /* compute the minimum overlap; */
2911 overlap = MIN(left, right);
2912 assert(overlap > 0);
2913 assert(overlap <= end - begin);
2914 assert(overlap <= duration);
2915
2916 if( usebdwidening )
2917 {
2918 assert(boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2919 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2920 }
2921 else
2922 {
2923 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2924 }
2925 }
2926 else
2927 {
2928 int ect;
2929
2930 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2931
2932 /* get the earliest completion time of the infer start time variable before the propagation took place */
2933 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2934
2935 /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2936 * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2937 * the job is scheduled w.r.t. its earliest start time
2938 */
2939 assert(ect > begin);
2940
2941 /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2942 * interval (before the propagation)
2943 */
2944 left = MIN3(ect - begin, end - begin, duration);
2945
2946 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2947 assert(left > 0);
2948
2949 est = boundedConvertRealToInt(scip, relaxedbd);
2950 assert(end >= est);
2951 assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
2952
2953 /* compute the overlap of the job after the propagation but considering the relaxed bound */
2954 right = MIN(end - est + 1, end - begin);
2955 assert(right > 0);
2956
2957 /* compute the minimum overlap */
2958 overlap = MIN(left, right);
2959 assert(overlap > 0);
2960 assert(overlap <= end - begin);
2961 assert(overlap <= duration);
2962
2963 if( usebdwidening )
2964 {
2965 assert(boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
2966 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
2967 }
2968 else
2969 {
2970 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2971 }
2972 }
2973
2974 /* subtract the amount of energy which is available due to the overlap of the inference start time */
2975 requiredenergy -= (SCIP_Longint) overlap * demand;
2976
2977 if( explanation != NULL )
2978 explanation[v] = TRUE;
2979
2980 continue;
2981 }
2982
2983 /* global time points */
2986
2987 glbenergy = 0;
2988
2989 /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
2990 * time window
2991 */
2992 if( est + duration > begin && lst < end )
2993 {
2994 /* evaluated global contribution */
2995 glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
2996
2997 /* remove the globally available energy form the required energy */
2998 requiredenergy -= glbenergy;
2999
3000 if( explanation != NULL )
3001 explanation[v] = TRUE;
3002 }
3003
3004 /* local time points */
3007
3008 /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3009 * time window
3010 */
3011 if( est + duration > begin && lst < end )
3012 {
3013 overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3014
3015 /* evaluated additionally local energy contribution */
3016 locenergies[v] = overlaps[v] * demand - glbenergy;
3017 assert(locenergies[v] >= 0);
3018 }
3019 }
3020
3021 /* sort the variable contributions w.r.t. additional local energy contributions */
3022 SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3023
3024 /* add local energy contributions until an overload is implied */
3025 for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3026 {
3027 SCIP_VAR* var;
3028 int duration;
3029 int overlap;
3030 int relaxlb;
3031 int relaxub;
3032 int idx;
3033
3034 idx = idxs[v];
3035 assert(idx >= 0 && idx < nvars);
3036
3037 var = vars[idx];
3038 assert(var != NULL);
3039 assert(var != infervar);
3040
3041 duration = durations[idx];
3042 assert(duration > 0);
3043
3044 overlap = overlaps[v];
3045 assert(overlap > 0);
3046
3047 requiredenergy -= locenergies[v];
3048
3049 if( requiredenergy < -1 )
3050 {
3051 int demand;
3052
3053 demand = demands[idx];
3054 assert(demand > 0);
3055
3056 overlap += (int)((requiredenergy + 1) / demand);
3057
3058#ifndef NDEBUG
3059 requiredenergy += locenergies[v];
3060 requiredenergy -= (SCIP_Longint) overlap * demand;
3061 assert(requiredenergy < 0);
3062#endif
3063 }
3064 assert(overlap > 0);
3065
3066 relaxlb = begin - duration + overlap;
3067 relaxub = end - overlap;
3068
3069 SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3074 relaxlb, relaxub, demands[idx], duration);
3075
3076 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3077 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3078
3079 if( explanation != NULL )
3080 explanation[idx] = TRUE;
3081 }
3082
3083 assert(requiredenergy < 0);
3084
3085 SCIPfreeBufferArray(scip, &idxs);
3086 SCIPfreeBufferArray(scip, &overlaps);
3087 SCIPfreeBufferArray(scip, &locenergies);
3088
3089 return SCIP_OKAY;
3090}
3091
3092/** resolve propagation w.r.t. the cumulative condition */
3093static
3095 SCIP* scip, /**< SCIP data structure */
3096 int nvars, /**< number of start time variables (activities) */
3097 SCIP_VAR** vars, /**< array of start time variables */
3098 int* durations, /**< array of durations */
3099 int* demands, /**< array of demands */
3100 int capacity, /**< cumulative capacity */
3101 int hmin, /**< left bound of time axis to be considered (including hmin) */
3102 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3103 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3104 INFERINFO inferinfo, /**< the user information */
3105 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3106 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3107 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3108 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3109 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3110 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3111 )
3112{
3113 switch( inferInfoGetProprule(inferinfo) )
3114 {
3116 {
3117 int inferdemand;
3118 int inferduration;
3119 int inferpos;
3120 int inferpeak;
3121 int relaxedpeak;
3122 int provedpeak;
3123
3124 /* get the position of the inferred variable in the vars array */
3125 inferpos = inferInfoGetData1(inferinfo);
3126 if( inferpos >= nvars || vars[inferpos] != infervar )
3127 {
3128 /* find inference variable in constraint */
3129 for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3130 {}
3131 }
3132 assert(inferpos < nvars);
3133 assert(vars[inferpos] == infervar);
3134
3135 inferdemand = demands[inferpos];
3136 inferduration = durations[inferpos];
3137
3138 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3139 {
3140 /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3141 * the inference variable
3142 */
3143 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3144
3145 SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3146 SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3147 SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3148
3149 /* get the inference peak that the time point which lead to the that propagtion */
3150 inferpeak = inferInfoGetData2(inferinfo);
3151 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3152 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3153 */
3154 assert(
3155 boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3156 relaxedpeak = boundedConvertRealToInt(scip, relaxedbd) + inferduration;
3157
3158 /* make sure that the relaxed peak is part of the effective horizon */
3159 relaxedpeak = MIN(relaxedpeak, hmax-1);
3160
3161 /* make sure that relaxed peak is not larger than the infer peak
3162 *
3163 * This can happen in case the variable is not an active variable!
3164 */
3165 relaxedpeak = MAX(relaxedpeak, inferpeak);
3166 assert(relaxedpeak >= inferpeak);
3167 assert(relaxedpeak >= hmin);
3168 }
3169 else
3170 {
3171 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3172
3173 SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3174 SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3175 SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3176
3177 /* get the time interval where the job could not be scheduled */
3178 inferpeak = inferInfoGetData2(inferinfo);
3179 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3180 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3181 */
3182 assert(boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3183 relaxedpeak = boundedConvertRealToInt(scip, relaxedbd) - 1;
3184
3185 /* make sure that the relaxed peak is part of the effective horizon */
3186 relaxedpeak = MAX(relaxedpeak, hmin);
3187
3188 /* make sure that relaxed peak is not larger than the infer peak
3189 *
3190 * This can happen in case the variable is not an active variable!
3191 */
3192 relaxedpeak = MIN(relaxedpeak, inferpeak);
3193 assert(relaxedpeak < hmax);
3194 }
3195
3196 /* resolves the propagation of the core time algorithm */
3197 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3198 infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3199
3200 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3201 {
3202 if( usebdwidening )
3203 {
3204 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3205 }
3206 else
3207 {
3208 /* old upper bound of variable itself is part of the explanation */
3209 SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3210 }
3211 }
3212 else
3213 {
3214 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3215
3216 if( usebdwidening )
3217 {
3218 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3219 }
3220 else
3221 {
3222 /* old lower bound of variable itself is part of the explanation */
3223 SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3224 }
3225 }
3226
3227 if( explanation != NULL )
3228 explanation[inferpos] = TRUE;
3229
3230 break;
3231 }
3233 case PROPRULE_3_TTEF:
3234 {
3235 int begin;
3236 int end;
3237
3238 begin = inferInfoGetData1(inferinfo);
3239 end = inferInfoGetData2(inferinfo);
3240 assert(begin < end);
3241
3242 begin = MAX(begin, hmin);
3243 end = MIN(end, hmax);
3244
3245 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3246 begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3247
3248 break;
3249 }
3250
3251 case PROPRULE_0_INVALID:
3252 default:
3253 SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3254 SCIPABORT();
3255 return SCIP_INVALIDDATA; /*lint !e527*/
3256 }
3257
3258 (*result) = SCIP_SUCCESS;
3259
3260 return SCIP_OKAY;
3261}
3262
3263/**@} */
3264
3265
3266/**@name Enforcement methods
3267 *
3268 * @{
3269 */
3270
3271/** apply all fixings which are given by the alternative bounds */
3272static
3274 SCIP* scip, /**< SCIP data structure */
3275 SCIP_VAR** vars, /**< array of active variables */
3276 int nvars, /**< number of active variables */
3277 int* alternativelbs, /**< alternative lower bounds */
3278 int* alternativeubs, /**< alternative lower bounds */
3279 int* downlocks, /**< number of constraints with down lock participating by the computation */
3280 int* uplocks, /**< number of constraints with up lock participating by the computation */
3281 SCIP_Bool* branched /**< pointer to store if a branching was applied */
3282 )
3283{
3284 int v;
3285
3286 for( v = 0; v < nvars; ++v )
3287 {
3288 SCIP_VAR* var;
3290
3291 var = vars[v];
3292 assert(var != NULL);
3293
3295
3297 {
3298 int ub;
3299
3301
3302 if( alternativelbs[v] <= ub )
3303 {
3305 (*branched) = TRUE;
3306
3307 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3308 SCIPvarGetLbLocal(var), alternativelbs[v]);
3309
3310 return SCIP_OKAY;
3311 }
3312 }
3313
3315 {
3316 int lb;
3317
3319
3320 if( alternativeubs[v] >= lb )
3321 {
3323 (*branched) = TRUE;
3324
3325 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3326 alternativeubs[v], SCIPvarGetUbLocal(var));
3327
3328 return SCIP_OKAY;
3329 }
3330 }
3331 }
3332
3333 return SCIP_OKAY;
3334}
3335
3336/** remove the capacity requirments for all job which start at the curtime */
3337static
3339 SCIP_CONSDATA* consdata, /**< constraint data */
3340 int curtime, /**< current point in time */
3341 int* starttimes, /**< array of start times */
3342 int* startindices, /**< permutation with respect to the start times */
3343 int* freecapacity, /**< pointer to store the resulting free capacity */
3344 int* idx, /**< pointer to index in start time array */
3345 int nvars /**< number of vars in array of starttimes and startindices */
3346 )
3347{
3348#if defined SCIP_DEBUG && !defined NDEBUG
3349 int oldidx;
3350
3351 assert(idx != NULL);
3352 oldidx = *idx;
3353#else
3354 assert(idx != NULL);
3355#endif
3356
3357 assert(starttimes != NULL);
3358 assert(starttimes != NULL);
3359 assert(freecapacity != NULL);
3360 assert(starttimes[*idx] == curtime);
3361 assert(consdata->demands != NULL);
3362 assert(freecapacity != idx);
3363
3364 /* subtract all capacity needed up to this point */
3365 (*freecapacity) -= consdata->demands[startindices[*idx]];
3366
3367 while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3368 {
3369 ++(*idx);
3370 (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3371 assert(freecapacity != idx);
3372 }
3373#ifdef SCIP_DEBUG
3374 assert(oldidx <= *idx);
3375#endif
3376}
3377
3378/** add the capacity requirments for all job which end at the curtime */
3379static
3381 SCIP_CONSDATA* consdata, /**< constraint data */
3382 int curtime, /**< current point in time */
3383 int* endtimes, /**< array of end times */
3384 int* endindices, /**< permutation with rspect to the end times */
3385 int* freecapacity, /**< pointer to store the resulting free capacity */
3386 int* idx, /**< pointer to index in end time array */
3387 int nvars /**< number of vars in array of starttimes and startindices */
3388 )
3389{
3390#if defined SCIP_DEBUG && !defined NDEBUG
3391 int oldidx;
3392 oldidx = *idx;
3393#endif
3394
3395 /* free all capacity usages of jobs the are no longer running */
3396 while( endtimes[*idx] <= curtime && *idx < nvars)
3397 {
3398 (*freecapacity) += consdata->demands[endindices[*idx]];
3399 ++(*idx);
3400 }
3401
3402#ifdef SCIP_DEBUG
3403 assert(oldidx <= *idx);
3404#endif
3405}
3406
3407/** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3408static
3410 SCIP* scip, /**< SCIP data structure */
3411 SCIP_CONSDATA* consdata, /**< constraint handler data */
3412 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3413 int* timepoint /**< pointer to store the time point of the peak */
3414 )
3415{
3416 int* starttimes; /* stores when each job is starting */
3417 int* endtimes; /* stores when each job ends */
3418 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3419 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3420
3421 int nvars; /* number of activities for this constraint */
3422 int freecapacity; /* remaining capacity */
3423 int curtime; /* point in time which we are just checking */
3424 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3425
3426 int hmin;
3427 int hmax;
3428
3429 int j;
3430
3431 assert(consdata != NULL);
3432
3433 nvars = consdata->nvars;
3434 assert(nvars > 0);
3435
3436 *timepoint = consdata->hmax;
3437
3438 assert(consdata->vars != NULL);
3439
3440 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3441 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3442 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3443 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3444
3445 /* create event point arrays */
3446 createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3447 starttimes, endtimes, startindices, endindices);
3448
3449 endindex = 0;
3450 freecapacity = consdata->capacity;
3451 hmin = consdata->hmin;
3452 hmax = consdata->hmax;
3453
3454 /* check each startpoint of a job whether the capacity is kept or not */
3455 for( j = 0; j < nvars; ++j )
3456 {
3457 curtime = starttimes[j];
3458 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3459
3460 if( curtime >= hmax )
3461 break;
3462
3463 /* remove the capacity requirments for all job which start at the curtime */
3464 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3465
3466 /* add the capacity requirments for all job which end at the curtime */
3467 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3468
3469 assert(freecapacity <= consdata->capacity);
3470 assert(endindex <= nvars);
3471
3472 /* endindex - points to the next job which will finish */
3473 /* j - points to the last job that has been released */
3474
3475 /* if free capacity is smaller than zero, then add branching candidates */
3476 if( freecapacity < 0 && curtime >= hmin )
3477 {
3478 *timepoint = curtime;
3479 break;
3480 }
3481 } /*lint --e{850}*/
3482
3483 /* free all buffer arrays */
3484 SCIPfreeBufferArray(scip, &endindices);
3485 SCIPfreeBufferArray(scip, &startindices);
3486 SCIPfreeBufferArray(scip, &endtimes);
3487 SCIPfreeBufferArray(scip, &starttimes);
3488
3489 return SCIP_OKAY;
3490}
3491
3492/** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3493static
3495 SCIP* scip, /**< SCIP data structure */
3496 SCIP_CONS** conss, /**< constraints to be processed */
3497 int nconss, /**< number of constraints */
3498 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3499 int* nbranchcands /**< pointer to store the number of branching variables */
3500 )
3501{
3502 SCIP_HASHTABLE* collectedvars;
3503 int c;
3504
3505 assert(scip != NULL);
3506 assert(conss != NULL);
3507
3508 /* create a hash table */
3510 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3511
3512 assert(scip != NULL);
3513 assert(conss != NULL);
3514
3515 for( c = 0; c < nconss; ++c )
3516 {
3517 SCIP_CONS* cons;
3518 SCIP_CONSDATA* consdata;
3519
3520 int curtime;
3521 int j;
3522
3523 cons = conss[c];
3524 assert(cons != NULL);
3525
3526 if( !SCIPconsIsActive(cons) )
3527 continue;
3528
3529 consdata = SCIPconsGetData(cons);
3530 assert(consdata != NULL);
3531
3532 /* get point in time when capacity is exceeded */
3533 SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3534
3535 if( curtime < consdata->hmin || curtime >= consdata->hmax )
3536 continue;
3537
3538 /* report all variables that are running at that point in time */
3539 for( j = 0; j < consdata->nvars; ++j )
3540 {
3541 SCIP_VAR* var;
3542 int lb;
3543 int ub;
3544
3545 var = consdata->vars[j];
3546 assert(var != NULL);
3547
3548 /* check if the variable was already added */
3549 if( SCIPhashtableExists(collectedvars, (void*)var) )
3550 continue;
3551
3554
3555 if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3556 {
3557 SCIP_Real solval;
3558 SCIP_Real score;
3559
3560 solval = SCIPgetSolVal(scip, sol, var);
3561 score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3562
3563 SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3564 SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3565 (*nbranchcands)++;
3566
3567 SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3568 }
3569 }
3570 }
3571
3572 SCIPhashtableFree(&collectedvars);
3573
3574 SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3575
3576 return SCIP_OKAY;
3577}
3578
3579/** enforcement of an LP, pseudo, or relaxation solution */
3580static
3582 SCIP* scip, /**< SCIP data structure */
3583 SCIP_CONS** conss, /**< constraints to be processed */
3584 int nconss, /**< number of constraints */
3585 SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3586 SCIP_Bool branch, /**< should branching candidates be collected */
3587 SCIP_RESULT* result /**< pointer to store the result */
3588 )
3589{
3590 if( branch )
3591 {
3592 int nbranchcands;
3593
3594 nbranchcands = 0;
3595 SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3596
3597 if( nbranchcands > 0 )
3598 (*result) = SCIP_INFEASIBLE;
3599 }
3600 else
3601 {
3602 SCIP_Bool violated;
3603 int c;
3604
3605 violated = FALSE;
3606
3607 /* first check if a constraints is violated */
3608 for( c = 0; c < nconss && !violated; ++c )
3609 {
3610 SCIP_CONS* cons;
3611
3612 cons = conss[c];
3613 assert(cons != NULL);
3614
3615 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3616 }
3617
3618 if( violated )
3619 (*result) = SCIP_INFEASIBLE;
3620 }
3621
3622 return SCIP_OKAY;
3623}
3624
3625/**@} */
3626
3627/**@name Propagation
3628 *
3629 * @{
3630 */
3631
3632/** check if cumulative constraint is independently of all other constraints */
3633static
3635 SCIP_CONS* cons /**< cumulative constraint */
3636 )
3637{
3638 SCIP_CONSDATA* consdata;
3639 SCIP_VAR** vars;
3640 SCIP_Bool* downlocks;
3641 SCIP_Bool* uplocks;
3642 int nvars;
3643 int v;
3644
3645 consdata = SCIPconsGetData(cons);
3646 assert(consdata != NULL);
3647
3648 nvars = consdata->nvars;
3649 vars = consdata->vars;
3650 downlocks = consdata->downlocks;
3651 uplocks = consdata->uplocks;
3652
3653 /* check if the cumulative constraint has the only locks on the involved variables */
3654 for( v = 0; v < nvars; ++v )
3655 {
3656 SCIP_VAR* var;
3657
3658 var = vars[v];
3659 assert(var != NULL);
3660
3661 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3662 || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3663 return FALSE;
3664 }
3665
3666 return TRUE;
3667}
3668
3669/** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3670 * (dual reductions)
3671 */
3672static
3674 SCIP* scip, /**< SCIP data structure */
3675 SCIP_CONS* cons, /**< cumulative constraint */
3676 SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3677 int* nchgbds, /**< pointer to store the number changed variable bounds */
3678 int* nfixedvars, /**< pointer to count number of fixings */
3679 int* ndelconss, /**< pointer to count number of deleted constraints */
3680 SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3681 SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3682 )
3683{
3684 SCIP_CONSDATA* consdata;
3685 SCIP_VAR** vars;
3686 SCIP_Real* objvals;
3687 SCIP_Real* lbs;
3688 SCIP_Real* ubs;
3689 SCIP_Real timelimit;
3690 SCIP_Real memorylimit;
3691 SCIP_Bool solved;
3692 SCIP_Bool error;
3693
3694 int ncheckconss;
3695 int nvars;
3696 int v;
3697
3698 assert(scip != NULL);
3701
3702 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3703 * would/could end in an implication which can lead to cutoff of the/all optimal solution
3704 */
3706 return SCIP_OKAY;
3707
3708 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3709 * use the locks to decide for a dual reduction using this constraint;
3710 */
3711 if( !SCIPconsIsChecked(cons) )
3712 return SCIP_OKAY;
3713
3714 ncheckconss = SCIPgetNCheckConss(scip);
3715
3716 /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3717 * presolved problem do nothing execpt to change the parameter settings
3718 */
3719 if( ncheckconss == 1 )
3720 {
3721 /* shrink the minimal maximum value for the conflict length */
3722 SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3723
3724 /* use only first unique implication point */
3725 SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3726
3727 /* do not use reconversion conflicts */
3728 SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3729
3730 /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3731 SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3732
3733 /* increase the number of conflicts which induce a restart */
3734 SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3735
3736 /* weight the variable which made into a conflict */
3737 SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3738
3739 /* do not check pseudo solution (for performance reasons) */
3740 SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3741
3742 /* use value based history to detect a reasonable branching point */
3743 SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3744
3745 /* turn of LP relaxation */
3746 SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3747
3748 /* prefer the down branch in case the value based history does not suggest something */
3749 SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3750
3751 /* accept any bound change */
3752 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3753
3754 /* allow for at most 10 restart, after that the value based history should be reliable */
3755 SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3756
3757 /* set priority for depth first search to highest possible value */
3758 SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3759
3760 return SCIP_OKAY;
3761 }
3762
3763 consdata = SCIPconsGetData(cons);
3764 assert(consdata != NULL);
3765
3766 /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3767 * fail on the first place
3768 */
3769 if( consdata->triedsolving )
3770 return SCIP_OKAY;
3771
3772 /* check if constraint is independently */
3773 if( !isConsIndependently(cons) )
3774 return SCIP_OKAY;
3775
3776 /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3777 * constraint is deleted; otherwise, we want to ensure that we do not try that again
3778 */
3779 consdata->triedsolving = TRUE;
3780
3781 SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3784
3785 nvars = consdata->nvars;
3786 vars = consdata->vars;
3787
3791
3792 for( v = 0; v < nvars; ++v )
3793 {
3794 SCIP_VAR* var;
3795
3796 /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3797 * array
3798 */
3799 var = vars[v];
3800 assert(var != NULL);
3801
3802 lbs[v] = SCIPvarGetLbLocal(var);
3803 ubs[v] = SCIPvarGetUbLocal(var);
3804
3805 objvals[v] = SCIPvarGetObj(var);
3806 }
3807
3808 /* check whether there is enough time and memory left */
3809 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3810 if( !SCIPisInfinity(scip, timelimit) )
3811 timelimit -= SCIPgetSolvingTime(scip);
3812 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3813
3814 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3815 if( !SCIPisInfinity(scip, memorylimit) )
3816 {
3817 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3818 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3819 }
3820
3821 /* solve the cumulative condition separately */
3822 SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3823 consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3824
3825 if( !(*cutoff) && !(*unbounded) && !error )
3826 {
3827 SCIP_Bool infeasible;
3828 SCIP_Bool tightened;
3829 SCIP_Bool allfixed;
3830
3831 allfixed = TRUE;
3832
3833 for( v = 0; v < nvars; ++v )
3834 {
3835 /* check if variable is fixed */
3836 if( lbs[v] + 0.5 > ubs[v] )
3837 {
3838 SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3839 assert(!infeasible);
3840
3841 if( tightened )
3842 {
3843 (*nfixedvars)++;
3844 consdata->triedsolving = FALSE;
3845 }
3846 }
3847 else
3848 {
3849 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3850 assert(!infeasible);
3851
3852 if( tightened )
3853 {
3854 (*nchgbds)++;
3855 consdata->triedsolving = FALSE;
3856 }
3857
3858 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3859 assert(!infeasible);
3860
3861 if( tightened )
3862 {
3863 (*nchgbds)++;
3864 consdata->triedsolving = FALSE;
3865 }
3866
3867 allfixed = FALSE;
3868 }
3869 }
3870
3871 /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3872 if( allfixed )
3873 {
3875 (*ndelconss)++;
3876 }
3877 }
3878
3879 SCIPfreeBufferArray(scip, &objvals);
3882
3883 return SCIP_OKAY;
3884}
3885
3886/** start conflict analysis to analysis the core insertion which is infeasible */
3887static
3889 SCIP* scip, /**< SCIP data structure */
3890 int nvars, /**< number of start time variables (activities) */
3891 SCIP_VAR** vars, /**< array of start time variables */
3892 int* durations, /**< array of durations */
3893 int* demands, /**< array of demands */
3894 int capacity, /**< cumulative capacity */
3895 int hmin, /**< left bound of time axis to be considered (including hmin) */
3896 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3897 SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3898 int inferduration, /**< duration of the start time variable */
3899 int inferdemand, /**< demand of the start time variable */
3900 int inferpeak, /**< profile preak which causes the infeasibilty */
3901 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3902 SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3903 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3904 )
3905{
3906 SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3907 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3908 SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3909
3910 /* initialize conflict analysis if conflict analysis is applicable */
3912 {
3914
3915 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3916 infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3917
3918 SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3919
3920 /* add both bound of the inference variable since these biuld the core which we could not inserted */
3921 if( usebdwidening )
3922 {
3923 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3924 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3925 }
3926 else
3927 {
3928 SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3929 SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3930 }
3931
3932 *initialized = TRUE;
3933 }
3934
3935 return SCIP_OKAY;
3936}
3937
3938/** We are using the core resource profile which contains all core except the one of the start time variable which we
3939 * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3940 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3941 * analysis
3942 */
3943static
3945 SCIP* scip, /**< SCIP data structure */
3946 int nvars, /**< number of start time variables (activities) */
3947 SCIP_VAR** vars, /**< array of start time variables */
3948 int* durations, /**< array of durations */
3949 int* demands, /**< array of demands */
3950 int capacity, /**< cumulative capacity */
3951 int hmin, /**< left bound of time axis to be considered (including hmin) */
3952 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3953 SCIP_CONS* cons, /**< constraint which is propagated */
3954 SCIP_PROFILE* profile, /**< resource profile */
3955 int idx, /**< position of the variable to propagate */
3956 int* nchgbds, /**< pointer to store the number of bound changes */
3957 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3958 SCIP_Bool* initialized, /**< was conflict analysis initialized */
3959 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3960 SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
3961 )
3962{
3963 SCIP_VAR* var;
3964 int ntimepoints;
3965 int duration;
3966 int demand;
3967 int peak;
3968 int newlb;
3969 int est;
3970 int lst;
3971 int pos;
3972
3973 var = vars[idx];
3974 assert(var != NULL);
3975
3976 duration = durations[idx];
3977 assert(duration > 0);
3978
3979 demand = demands[idx];
3980 assert(demand > 0);
3981
3984 ntimepoints = SCIPprofileGetNTimepoints(profile);
3985
3986 /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
3987 * load which we have at the earliest start time (lower bound)
3988 */
3989 (void) SCIPprofileFindLeft(profile, est, &pos);
3990
3991 SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
3992
3993 /* we now trying to move the earliest start time in steps of at most "duration" length */
3994 do
3995 {
3996 INFERINFO inferinfo;
3997 SCIP_Bool tightened;
3998 int ect;
3999
4000#ifndef NDEBUG
4001 {
4002 /* in debug mode we check that we adjust the search position correctly */
4003 int tmppos;
4004
4005 (void)SCIPprofileFindLeft(profile, est, &tmppos);
4006 assert(pos == tmppos);
4007 }
4008#endif
4009 ect = est + duration;
4010 peak = -1;
4011
4012 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4013 * want a peak which is closest to the earliest completion time
4014 */
4015 do
4016 {
4017 /* check if the profile load conflicts with the demand of the start time variable */
4018 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4019 peak = pos;
4020
4021 pos++;
4022 }
4023 while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4024
4025 /* if we found no peak that means current the job could be scheduled at its earliest start time without
4026 * conflicting to the core resource profile
4027 */
4028 /* coverity[check_after_sink] */
4029 if( peak == -1 )
4030 break;
4031
4032 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4033 * profile. That means we have to move it to the next time point in the resource profile but at most to the
4034 * earliest completion time (the remaining move will done in the next loop)
4035 */
4036 newlb = SCIPprofileGetTime(profile, peak+1);
4037 newlb = MIN(newlb, ect);
4038
4039 /* if the earliest start time is greater than the lst we detected an infeasibilty */
4040 if( newlb > lst )
4041 {
4042 SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4043
4044 /* use conflict analysis to analysis the core insertion which was infeasible */
4045 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4046 var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4047
4048 if( explanation != NULL )
4049 explanation[idx] = TRUE;
4050
4051 *infeasible = TRUE;
4052
4053 break;
4054 }
4055
4056 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4057 * bound change
4058 */
4059 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4060
4061 /* perform the bound lower bound change */
4062 if( inferInfoIsValid(inferinfo) )
4063 {
4064 SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4065 }
4066 else
4067 {
4068 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4069 }
4070 assert(tightened);
4071 assert(!(*infeasible));
4072
4073 SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4074 (*nchgbds)++;
4075
4076 /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4078
4079 /* adjust the earliest start time
4080 *
4081 * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4082 * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4083 * involved.
4084 */
4086 assert(est >= newlb);
4087
4088 /* adjust the search position for the resource profile for the next step */
4089 if( est == SCIPprofileGetTime(profile, peak+1) )
4090 pos = peak + 1;
4091 else
4092 pos = peak;
4093 }
4094 while( est < lst );
4095
4096 return SCIP_OKAY;
4097}
4098
4099/** We are using the core resource profile which contains all core except the one of the start time variable which we
4100 * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4101 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4102 * analysis
4103 */
4104static
4106 SCIP* scip, /**< SCIP data structure */
4107 SCIP_VAR* var, /**< start time variable to propagate */
4108 int duration, /**< duration of the job */
4109 int demand, /**< demand of the job */
4110 int capacity, /**< cumulative capacity */
4111 SCIP_CONS* cons, /**< constraint which is propagated */
4112 SCIP_PROFILE* profile, /**< resource profile */
4113 int idx, /**< position of the variable to propagate */
4114 int* nchgbds /**< pointer to store the number of bound changes */
4115 )
4116{
4117 int ntimepoints;
4118 int newub;
4119 int peak;
4120 int pos;
4121 int est;
4122 int lst;
4123 int lct;
4124
4125 assert(var != NULL);
4126 assert(duration > 0);
4127 assert(demand > 0);
4128
4131
4132 /* in case the start time variable is fixed do nothing */
4133 if( est == lst )
4134 return SCIP_OKAY;
4135
4136 ntimepoints = SCIPprofileGetNTimepoints(profile);
4137
4138 lct = lst + duration;
4139
4140 /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4141 * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4142 * position gives us the load which we have at the latest completion time minus one
4143 */
4144 (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4145
4146 SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4148
4149 if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4150 return SCIP_OKAY;
4151
4152 /* we now trying to move the latest start time in steps of at most "duration" length */
4153 do
4154 {
4155 INFERINFO inferinfo;
4156 SCIP_Bool tightened;
4157 SCIP_Bool infeasible;
4158
4159 peak = -1;
4160
4161#ifndef NDEBUG
4162 {
4163 /* in debug mode we check that we adjust the search position correctly */
4164 int tmppos;
4165
4166 (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4167 assert(pos == tmppos);
4168 }
4169#endif
4170
4171 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4172 * want a peak which is closest to the latest start time
4173 */
4174 do
4175 {
4176 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4177 peak = pos;
4178
4179 pos--;
4180 }
4181 while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4182
4183 /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4184 * to the core resource profile
4185 */
4186 /* coverity[check_after_sink] */
4187 if( peak == -1 )
4188 break;
4189
4190 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4191 * profile. That means the job has be done until that point. Hence that gives us the latest completion
4192 * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4193 * doing in the next loop)
4194 */
4195 newub = SCIPprofileGetTime(profile, peak);
4196 newub = MAX(newub, lst) - duration;
4197 assert(newub >= est);
4198
4199 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4200 * bound change
4201 */
4202 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4203
4204 /* perform the bound upper bound change */
4205 if( inferInfoIsValid(inferinfo) )
4206 {
4207 SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4208 }
4209 else
4210 {
4211 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4212 }
4213 assert(tightened);
4214 assert(!infeasible);
4215
4216 SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4217 (*nchgbds)++;
4218
4219 /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4221
4222 /* adjust the latest start and completion time
4223 *
4224 * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4225 * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4226 * involved.
4227 */
4229 assert(lst <= newub);
4230 lct = lst + duration;
4231
4232 /* adjust the search position for the resource profile for the next step */
4233 if( SCIPprofileGetTime(profile, peak) == lct )
4234 pos = peak - 1;
4235 else
4236 pos = peak;
4237 }
4238 while( est < lst );
4239
4240 return SCIP_OKAY;
4241}
4242
4243/** compute for the different earliest start and latest completion time the core energy of the corresponding time
4244 * points
4245 */
4246static
4248 SCIP_PROFILE* profile, /**< core profile */
4249 int nvars, /**< number of start time variables (activities) */
4250 int* ests, /**< array of sorted earliest start times */
4251 int* lcts, /**< array of sorted latest completion times */
4252 int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4253 int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4254 )
4255{
4256 int ntimepoints;
4257 int energy;
4258 int t;
4259 int v;
4260
4261 ntimepoints = SCIPprofileGetNTimepoints(profile);
4262 t = ntimepoints - 1;
4263 energy = 0;
4264
4265 /* compute core energy after the earliest start time of each job */
4266 for( v = nvars-1; v >= 0; --v )
4267 {
4268 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4269 {
4270 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4271 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4272 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4273 t--;
4274 }
4275 assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4276
4277 /* maybe ests[j] is in-between two timepoints */
4278 if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4279 {
4280 assert(t > 0);
4281 coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4282 }
4283 else
4284 coreEnergyAfterEst[v] = energy;
4285 }
4286
4287 t = ntimepoints - 1;
4288 energy = 0;
4289
4290 /* compute core energy after the latest completion time of each job */
4291 for( v = nvars-1; v >= 0; --v )
4292 {
4293 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4294 {
4295 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4296 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4297 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4298 t--;
4299 }
4300 assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4301
4302 /* maybe lcts[j] is in-between two timepoints */
4303 if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4304 {
4305 assert(t > 0);
4306 coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4307 }
4308 else
4309 coreEnergyAfterLct[v] = energy;
4310 }
4311}
4312
4313/** collect earliest start times, latest completion time, and free energy contributions */
4314static
4316 SCIP* scip, /**< SCIP data structure */
4317 int nvars, /**< number of start time variables (activities) */
4318 SCIP_VAR** vars, /**< array of start time variables */
4319 int* durations, /**< array of durations */
4320 int* demands, /**< array of demands */
4321 int hmin, /**< left bound of time axis to be considered (including hmin) */
4322 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4323 int* permests, /**< array to store the variable positions */
4324 int* ests, /**< array to store earliest start times */
4325 int* permlcts, /**< array to store the variable positions */
4326 int* lcts, /**< array to store latest completion times */
4327 int* ects, /**< array to store earliest completion times of the flexible part of the job */
4328 int* lsts, /**< array to store latest start times of the flexible part of the job */
4329 int* flexenergies /**< array to store the flexible energies of each job */
4330 )
4331{
4332 int v;
4333
4334 for( v = 0; v < nvars; ++ v)
4335 {
4336 int duration;
4337 int leftadjust;
4338 int rightadjust;
4339 int core;
4340 int est;
4341 int lct;
4342 int ect;
4343 int lst;
4344
4345 duration = durations[v];
4346 assert(duration > 0);
4347
4350 ect = est + duration;
4351 lct = lst + duration;
4352
4353 ests[v] = est;
4354 lcts[v] = lct;
4355 permests[v] = v;
4356 permlcts[v] = v;
4357
4358 /* compute core time window which lies within the effective horizon */
4359 core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4360
4361 /* compute the number of time steps the job could run before the effective horizon */
4362 leftadjust = MAX(0, hmin - est);
4363
4364 /* compute the number of time steps the job could run after the effective horizon */
4365 rightadjust = MAX(0, lct - hmax);
4366
4367 /* compute for each job the energy which is flexible; meaning not part of the core */
4368 flexenergies[v] = duration - leftadjust - rightadjust - core;
4369 flexenergies[v] = MAX(0, flexenergies[v]);
4370 flexenergies[v] *= demands[v];
4371 assert(flexenergies[v] >= 0);
4372
4373 /* the earliest completion time of the flexible energy */
4374 ects[v] = MIN(ect, lst);
4375
4376 /* the latest start time of the flexible energy */
4377 lsts[v] = MAX(ect, lst);
4378 }
4379}
4380
4381/** try to tighten the lower bound of the given variable */
4382static
4384 SCIP* scip, /**< SCIP data structure */
4385 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4386 int nvars, /**< number of start time variables (activities) */
4387 SCIP_VAR** vars, /**< array of start time variables */
4388 int* durations, /**< array of durations */
4389 int* demands, /**< array of demands */
4390 int capacity, /**< cumulative capacity */
4391 int hmin, /**< left bound of time axis to be considered (including hmin) */
4392 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4393 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4394 int duration, /**< duration of the job */
4395 int demand, /**< demand of the job */
4396 int est, /**< earliest start time of the job */
4397 int ect, /**< earliest completion time of the flexible part of the job */
4398 int lct, /**< latest completion time of the job */
4399 int begin, /**< begin of the time window under investigation */
4400 int end, /**< end of the time window under investigation */
4401 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4402 int* bestlb, /**< pointer to strope the best lower bound change */
4403 int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4404 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4405 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4406 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4407 )
4408{
4409 int newlb;
4410
4411 assert(begin >= hmin);
4412 assert(end <= hmax);
4413
4414 /* check if the time-table edge-finding should infer bounds */
4415 if( !conshdlrdata->ttefinfer )
4416 return SCIP_OKAY;
4417
4418 /* if the job can be processed completely before or after the time window, nothing can be tightened */
4419 if( est >= end || ect <= begin )
4420 return SCIP_OKAY;
4421
4422 /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4423 * skip since the overload check will do the job
4424 */
4425 if( est >= begin && ect <= end )
4426 return SCIP_OKAY;
4427
4428 /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4429 * earliest start time
4430 */
4431 if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4432 return SCIP_OKAY;
4433
4434 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4435 * present; therefore, we need to add the core;
4436 *
4437 * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4438 * compute the earliest completion time of the (whole) job
4439 */
4440 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4441
4442 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4443 *
4444 * @note we can round down the compute duration w.r.t. the available energy
4445 */
4446 newlb = end - (int) (energy / demand);
4447
4448 /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4449 * bound (latest start time); meaning it is not possible to schedule the job
4450 */
4451 if( newlb > lct - duration )
4452 {
4453 /* initialize conflict analysis if conflict analysis is applicable */
4455 {
4456 SCIP_Real relaxedbd;
4457
4459
4460 /* it is enough to overshoot the upper bound of the variable by one */
4461 relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4462
4463 /* initialize conflict analysis */
4465
4466 /* added to upper bound (which was overcut be new lower bound) of the variable */
4468
4469 /* analyze the infeasible */
4470 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4471 begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4472
4473 (*initialized) = TRUE;
4474 }
4475
4476 (*cutoff) = TRUE;
4477 }
4478 else if( newlb > (*bestlb) )
4479 {
4480 INFERINFO inferinfo;
4481
4482 assert(newlb > begin);
4483
4484 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4485
4486 /* construct inference information */
4487 (*inferinfos) = inferInfoToInt(inferinfo);
4488 (*bestlb) = newlb;
4489 }
4490
4491 return SCIP_OKAY;
4492}
4493
4494/** try to tighten the upper bound of the given variable */
4495static
4497 SCIP* scip, /**< SCIP data structure */
4498 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4499 int nvars, /**< number of start time variables (activities) */
4500 SCIP_VAR** vars, /**< array of start time variables */
4501 int* durations, /**< array of durations */
4502 int* demands, /**< array of demands */
4503 int capacity, /**< cumulative capacity */
4504 int hmin, /**< left bound of time axis to be considered (including hmin) */
4505 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4506 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4507 int duration, /**< duration of the job */
4508 int demand, /**< demand of the job */
4509 int est, /**< earliest start time of the job */
4510 int lst, /**< latest start time of the flexible part of the job */
4511 int lct, /**< latest completion time of the job */
4512 int begin, /**< begin of the time window under investigation */
4513 int end, /**< end of the time window under investigation */
4514 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4515 int* bestub, /**< pointer to strope the best upper bound change */
4516 int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4517 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4518 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4519 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4520 )
4521{
4522 int newub;
4523
4524 assert(begin >= hmin);
4525 assert(end <= hmax);
4526 assert(est < begin);
4527
4528 /* check if the time-table edge-finding should infer bounds */
4529 if( !conshdlrdata->ttefinfer )
4530 return SCIP_OKAY;
4531
4532 /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4533 if( lst >= end || lct <= begin )
4534 return SCIP_OKAY;
4535
4536 /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4537 * skip since the overload check will do the job
4538 */
4539 if( lst >= begin && lct <= end )
4540 return SCIP_OKAY;
4541
4542 /* check if the available energy in the time window is to small to handle the flexible part of the job */
4543 if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4544 return SCIP_OKAY;
4545
4546 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4547 * present; therefore, we need to add the core;
4548 *
4549 * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4550 * latest start of the (whole) job
4551 */
4552 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4553 assert(energy >= 0);
4554
4555 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4556 *
4557 * @note we can round down the compute duration w.r.t. the available energy
4558 */
4559 assert(demand > 0);
4560 newub = begin - duration + (int) (energy / demand);
4561
4562 /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4563 * bound (earliest start time); meaning it is not possible to schedule the job
4564 */
4565 if( newub < est )
4566 {
4567 /* initialize conflict analysis if conflict analysis is applicable */
4569 {
4570 SCIP_Real relaxedbd;
4571
4573
4574 /* it is enough to undershoot the lower bound of the variable by one */
4575 relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4576
4577 /* initialize conflict analysis */
4579
4580 /* added to lower bound (which was undercut be new upper bound) of the variable */
4582
4583 /* analyze the infeasible */
4584 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4585 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4586
4587 (*initialized) = TRUE;
4588 }
4589
4590 (*cutoff) = TRUE;
4591 }
4592 else if( newub < (*bestub) )
4593 {
4594 INFERINFO inferinfo;
4595
4596 assert(newub < begin);
4597
4598 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4599
4600 /* construct inference information */
4601 (*inferinfos) = inferInfoToInt(inferinfo);
4602 (*bestub) = newub;
4603 }
4604
4605 return SCIP_OKAY;
4606}
4607
4608/** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4609static
4611 SCIP* scip, /**< SCIP data structure */
4612 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4613 int nvars, /**< number of start time variables (activities) */
4614 SCIP_VAR** vars, /**< array of start time variables */
4615 int* durations, /**< array of durations */
4616 int* demands, /**< array of demands */
4617 int capacity, /**< cumulative capacity */
4618 int hmin, /**< left bound of time axis to be considered (including hmin) */
4619 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4620 int* newlbs, /**< array to buffer new lower bounds */
4621 int* newubs, /**< array to buffer new upper bounds */
4622 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4623 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4624 int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4625 int* flexenergies, /**< array of flexible energies in the same order as the variables */
4626 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4627 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4628 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4629 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4630 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4631 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4632 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4633 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4634 )
4635{
4636 int coreEnergyAfterEnd;
4637 SCIP_Longint maxavailable;
4638 SCIP_Longint minavailable;
4639 SCIP_Longint totalenergy;
4640 int nests;
4641 int est;
4642 int lct;
4643 int start;
4644 int end;
4645 int v;
4646
4647 est = INT_MAX;
4648 lct = INT_MIN;
4649
4650 /* compute earliest start and latest completion time of all jobs */
4651 for( v = 0; v < nvars; ++v )
4652 {
4654 end = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4655
4656 est = MIN(est, start);
4657 lct = MAX(lct, end);
4658 }
4659
4660 /* adjust the effective time horizon */
4661 hmin = MAX(hmin, est);
4662 hmax = MIN(hmax, lct);
4663
4664 end = hmax + 1;
4665 coreEnergyAfterEnd = -1;
4666
4667 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4668 minavailable = maxavailable;
4669 totalenergy = computeTotalEnergy(durations, demands, nvars);
4670
4671 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4672 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4673 return SCIP_OKAY;
4674
4675 nests = nvars;
4676
4677 /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4678 * times define the end of the time interval under investigation
4679 */
4680 for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4681 {
4682 int flexenergy;
4683 int minbegin;
4684 int lbenergy;
4685 int lbcand;
4686 int i;
4687
4688 lct = lcts[v];
4689
4690 /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4691 * infinity capacity is available; hence we skip that
4692 */
4693 if( lct > hmax )
4694 continue;
4695
4696 /* if the latest completion time is smaller then hmin we have to stop */
4697 if( lct <= hmin )
4698 {
4699 assert(v == 0 || lcts[v-1] <= lcts[v]);
4700 break;
4701 }
4702
4703 /* if the latest completion time equals to previous end time, we can continue since this particular interval
4704 * induced by end was just analyzed
4705 */
4706 if( lct == end )
4707 continue;
4708
4709 assert(lct < end);
4710
4711 /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4712 * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4713 * free energy; if so it means that in the next iterate the free-energy cannot be negative
4714 */
4715 if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4716 {
4717 SCIP_Longint freeenergy;
4718
4719 assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4720 assert(coreEnergyAfterEnd >= 0);
4721
4722 /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4723 freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4724
4725 if( freeenergy <= minavailable )
4726 {
4727 SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4728 continue;
4729 }
4730 }
4731
4732 SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4733
4734 end = lct;
4735 coreEnergyAfterEnd = coreEnergyAfterLct[v];
4736
4737 flexenergy = 0;
4738 minavailable = maxavailable;
4739 minbegin = hmax;
4740 lbcand = -1;
4741 lbenergy = 0;
4742
4743 /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4744 * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4745 * wider
4746 */
4747 for( i = nests-1; i >= 0; --i )
4748 {
4749 SCIP_VAR* var;
4750 SCIP_Longint freeenergy;
4751 int duration;
4752 int demand;
4753 int begin;
4754 int idx;
4755 int lst;
4756
4757 idx = perm[i];
4758 assert(idx >= 0);
4759 assert(idx < nvars);
4760 assert(!(*cutoff));
4761
4762 /* the earliest start time of the job */
4763 est = ests[i];
4764
4765 /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4766 * latest completion times (which define end) are scant in non-increasing order
4767 */
4768 if( end <= est )
4769 {
4770 nests--;
4771 continue;
4772 }
4773
4774 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4775 * current ending time
4776 */
4777 if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4778 break;
4779
4780 var = vars[idx];
4781 assert(var != NULL);
4782
4783 duration = durations[idx];
4784 assert(duration > 0);
4785
4786 demand = demands[idx];
4787 assert(demand > 0);
4788
4790
4791 /* the latest start time of the free part of the job */
4792 lst = lsts[idx];
4793
4794 /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4795 * investigation; hence the overload check will do the the job
4796 */
4797 assert(est <= minbegin);
4798 if( minavailable < maxavailable && est < minbegin )
4799 {
4800 assert(!(*cutoff));
4801
4802 /* try to tighten the upper bound */
4803 SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4804 var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4805 initialized, explanation, cutoff) );
4806
4807 if( *cutoff )
4808 break;
4809 }
4810
4811 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4812 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4813
4814 begin = est;
4816
4817 /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4818 * free energy
4819 */
4820 if( begin < hmin )
4821 break;
4822
4823 /* compute the contribution to the flexible energy */
4824 if( lct <= end )
4825 {
4826 /* if the jobs has to finish before the end, all the energy has to be scheduled */
4827 assert(lst >= begin);
4828 assert(flexenergies[idx] >= 0);
4829 flexenergy += flexenergies[idx];
4830 }
4831 else
4832 {
4833 /* the job partly overlaps with the end */
4834 int candenergy;
4835 int energy;
4836
4837 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4838 * w.r.t. latest start time
4839 *
4840 * @note we need to be aware of the effective horizon
4841 */
4842 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4843 assert(end - lst < duration);
4844 assert(energy >= 0);
4845
4846 /* adjust the flexible energy of the time interval */
4847 flexenergy += energy;
4848
4849 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4850 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4851 assert(candenergy >= 0);
4852
4853 /* check if we found a better candidate */
4854 if( candenergy > lbenergy )
4855 {
4856 lbenergy = candenergy;
4857 lbcand = idx;
4858 }
4859 }
4860
4861 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4862 assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4863
4864 /* compute the energy which is not used yet */
4865 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4866
4867 /* check overload */
4868 if( freeenergy < 0 )
4869 {
4870 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4871
4872 /* initialize conflict analysis if conflict analysis is applicable */
4874 {
4875 /* analyze infeasibilty */
4877
4878 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4880 conshdlrdata->usebdwidening, explanation) );
4881
4882 (*initialized) = TRUE;
4883 }
4884
4885 (*cutoff) = TRUE;
4886
4887 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4889
4890 break;
4891 }
4892
4893 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4894 if( lbenergy > 0 && freeenergy < lbenergy )
4895 {
4896 SCIP_Longint energy;
4897 int newlb;
4898 int ect;
4899
4900 ect = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4902
4903 /* remove the energy of our job from the ... */
4904 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4905
4906 newlb = end - (int)(energy / demands[lbcand]);
4907
4908 if( newlb > lst )
4909 {
4910 /* initialize conflict analysis if conflict analysis is applicable */
4912 {
4913 SCIP_Real relaxedbd;
4914
4915 /* analyze infeasibilty */
4917
4918 relaxedbd = lst + 1.0;
4919
4920 /* added to upper bound (which was overcut be new lower bound) of the variable */
4922
4923 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4924 begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4925 conshdlrdata->usebdwidening, explanation) );
4926
4927 (*initialized) = TRUE;
4928 }
4929
4930 (*cutoff) = TRUE;
4931 break;
4932 }
4933 else if( newlb > newlbs[lbcand] )
4934 {
4935 INFERINFO inferinfo;
4936
4937 /* construct inference information */
4938 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4939
4940 /* buffer upper bound change */
4941 lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4942 newlbs[lbcand] = newlb;
4943 }
4944 }
4945
4946 /* check if the current interval has a smaller free energy */
4947 if( minavailable > freeenergy )
4948 {
4949 minavailable = freeenergy;
4950 minbegin = begin;
4951 }
4952 assert(minavailable >= 0);
4953 }
4954 }
4955
4956 return SCIP_OKAY;
4957}
4958
4959/** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4960static
4962 SCIP* scip, /**< SCIP data structure */
4963 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4964 int nvars, /**< number of start time variables (activities) */
4965 SCIP_VAR** vars, /**< array of start time variables */
4966 int* durations, /**< array of durations */
4967 int* demands, /**< array of demands */
4968 int capacity, /**< cumulative capacity */
4969 int hmin, /**< left bound of time axis to be considered (including hmin) */
4970 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4971 int* newlbs, /**< array to buffer new lower bounds */
4972 int* newubs, /**< array to buffer new upper bounds */
4973 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4974 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4975 int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
4976 int* flexenergies, /**< array of flexible energies in the same order as the variables */
4977 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
4978 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4979 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4980 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4981 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4982 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4983 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4984 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4985 )
4986{
4987 int coreEnergyAfterStart;
4988 SCIP_Longint maxavailable;
4989 SCIP_Longint minavailable;
4990 SCIP_Longint totalenergy;
4991 int nlcts;
4992 int begin;
4993 int minest;
4994 int maxlct;
4995 int start;
4996 int end;
4997 int v;
4998
4999 if( *cutoff )
5000 return SCIP_OKAY;
5001
5002 begin = hmin - 1;
5003
5004 minest = INT_MAX;
5005 maxlct = INT_MIN;
5006
5007 /* compute earliest start and latest completion time of all jobs */
5008 for( v = 0; v < nvars; ++v )
5009 {
5011 end = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5012
5013 minest = MIN(minest, start);
5014 maxlct = MAX(maxlct, end);
5015 }
5016
5017 /* adjust the effective time horizon */
5018 hmin = MAX(hmin, minest);
5019 hmax = MIN(hmax, maxlct);
5020
5021 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5022 totalenergy = computeTotalEnergy(durations, demands, nvars);
5023
5024 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5025 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5026 return SCIP_OKAY;
5027
5028 nlcts = 0;
5029
5030 /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5031 * define the start of the time interval under investigation
5032 */
5033 for( v = 0; v < nvars; ++v )
5034 {
5035 int flexenergy;
5036 int minend;
5037 int ubenergy;
5038 int ubcand;
5039 int est;
5040 int i;
5041
5042 est = ests[v];
5043
5044 /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5045 * infinity capacity is available; hence we skip that
5046 */
5047 if( est < hmin )
5048 continue;
5049
5050 /* if the earliest start time is larger or equal then hmax we have to stop */
5051 if( est >= hmax )
5052 break;
5053
5054 /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5055 * induced by start was just analyzed
5056 */
5057 if( est == begin )
5058 continue;
5059
5060 assert(est > begin);
5061
5062 SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5063
5064 begin = est;
5065 coreEnergyAfterStart = coreEnergyAfterEst[v];
5066
5067 flexenergy = 0;
5068 minavailable = maxavailable;
5069 minend = hmin;
5070 ubcand = -1;
5071 ubenergy = 0;
5072
5073 /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5074 * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5075 */
5076 for( i = nlcts; i < nvars; ++i )
5077 {
5078 SCIP_VAR* var;
5079 SCIP_Longint freeenergy;
5080 int duration;
5081 int demand;
5082 int idx;
5083 int lct;
5084 int ect;
5085
5086 idx = perm[i];
5087 assert(idx >= 0);
5088 assert(idx < nvars);
5089 assert(!(*cutoff));
5090
5091 /* the earliest start time of the job */
5092 lct = lcts[i];
5093
5094 /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5095 * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5096 */
5097 if( lct <= begin )
5098 {
5099 nlcts++;
5100 continue;
5101 }
5102
5103 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5104 * start with current beginning time
5105 */
5106 if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5107 break;
5108
5109 var = vars[idx];
5110 assert(var != NULL);
5111
5112 duration = durations[idx];
5113 assert(duration > 0);
5114
5115 demand = demands[idx];
5116 assert(demand > 0);
5117
5119
5120 /* the earliest completion time of the flexible part of the job */
5121 ect = ects[idx];
5122
5123 /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5124 * investigation; hence the overload check will do the the job
5125 */
5126 assert(lct >= minend);
5127 if( minavailable < maxavailable && lct > minend )
5128 {
5129 assert(!(*cutoff));
5130
5131 /* try to tighten the upper bound */
5132 SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5133 var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5134 initialized, explanation, cutoff) );
5135
5136 if( *cutoff )
5137 return SCIP_OKAY;
5138 }
5139
5140 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5141 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5142
5143 end = lct;
5145
5146 /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5147 * free energy
5148 */
5149 if( end > hmax )
5150 break;
5151
5152 /* compute the contribution to the flexible energy */
5153 if( est >= begin )
5154 {
5155 /* if the jobs has to finish before the end, all the energy has to be scheduled */
5156 assert(ect <= end);
5157 assert(flexenergies[idx] >= 0);
5158 flexenergy += flexenergies[idx];
5159 }
5160 else
5161 {
5162 /* the job partly overlaps with the end */
5163 int candenergy;
5164 int energy;
5165
5166 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5167 * w.r.t. latest start time
5168 *
5169 * @note we need to be aware of the effective horizon
5170 */
5171 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5172 assert(ect - begin < duration);
5173 assert(energy >= 0);
5174
5175 /* adjust the flexible energy of the time interval */
5176 flexenergy += energy;
5177
5178 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5179 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5180 assert(candenergy >= 0);
5181
5182 /* check if we found a better candidate */
5183 if( candenergy > ubenergy )
5184 {
5185 ubenergy = candenergy;
5186 ubcand = idx;
5187 }
5188 }
5189
5190 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5191 assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5192
5193 /* compute the energy which is not used yet */
5194 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5195
5196 /* check overload */
5197 if( freeenergy < 0 )
5198 {
5199 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5200
5201 /* initialize conflict analysis if conflict analysis is applicable */
5203 {
5204 /* analyze infeasibilty */
5206
5207 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5209 conshdlrdata->usebdwidening, explanation) );
5210
5211 (*initialized) = TRUE;
5212 }
5213
5214 (*cutoff) = TRUE;
5215
5216 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5218
5219 return SCIP_OKAY;
5220 }
5221
5222 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5223 if( ubenergy > 0 && freeenergy < ubenergy )
5224 {
5225 SCIP_Longint energy;
5226 int newub;
5227 int lst;
5228
5229 duration = durations[ubcand];
5230 assert(duration > 0);
5231
5232 ect = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5234
5235 /* remove the energy of our job from the ... */
5236 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5237
5238 newub = begin - duration + (int)(energy / demands[ubcand]);
5239
5240 if( newub < ect - duration )
5241 {
5242 /* initialize conflict analysis if conflict analysis is applicable */
5244 {
5245 SCIP_Real relaxedbd;
5246 /* analyze infeasibilty */
5248
5249 relaxedbd = ect - duration - 1.0;
5250
5251 /* added to lower bound (which was undercut be new upper bound) of the variable */
5253
5254 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5255 begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5256 conshdlrdata->usebdwidening, explanation) );
5257
5258 (*initialized) = TRUE;
5259 }
5260
5261 (*cutoff) = TRUE;
5262 return SCIP_OKAY;
5263 }
5264 else if( newub < newubs[ubcand] )
5265 {
5266 INFERINFO inferinfo;
5267
5268 /* construct inference information */
5269 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5270
5271 /* buffer upper bound change */
5272 ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5273 newubs[ubcand] = newub;
5274 }
5275 }
5276
5277 /* check if the current interval has a smaller free energy */
5278 if( minavailable > freeenergy )
5279 {
5280 minavailable = freeenergy;
5281 minend = end;
5282 }
5283 assert(minavailable >= 0);
5284 }
5285 }
5286
5287 return SCIP_OKAY;
5288}
5289
5290/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5291 * edge-finding
5292 *
5293 * @note The algorithm is based on the following two papers:
5294 * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5295 * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5296 * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5297 * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5298 * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5299 */
5300static
5302 SCIP* scip, /**< SCIP data structure */
5303 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5304 SCIP_PROFILE* profile, /**< current core profile */
5305 int nvars, /**< number of start time variables (activities) */
5306 SCIP_VAR** vars, /**< array of start time variables */
5307 int* durations, /**< array of durations */
5308 int* demands, /**< array of demands */
5309 int capacity, /**< cumulative capacity */
5310 int hmin, /**< left bound of time axis to be considered (including hmin) */
5311 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5312 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5313 int* nchgbds, /**< pointer to store the number of bound changes */
5314 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5315 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5316 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5317 )
5318{
5319 int* coreEnergyAfterEst;
5320 int* coreEnergyAfterLct;
5321 int* flexenergies;
5322 int* permests;
5323 int* permlcts;
5324 int* lcts;
5325 int* ests;
5326 int* ects;
5327 int* lsts;
5328
5329 int* newlbs;
5330 int* newubs;
5331 int* lbinferinfos;
5332 int* ubinferinfos;
5333
5334 int v;
5335
5336 /* check if a cutoff was already detected */
5337 if( (*cutoff) )
5338 return SCIP_OKAY;
5339
5340 /* check if at least the basic overload checking should be perfomed */
5341 if( !conshdlrdata->ttefcheck )
5342 return SCIP_OKAY;
5343
5344 SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5345
5346 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5347 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5348 SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5349 SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5350 SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5355
5358 SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5359 SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5360
5361 /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5362 for( v = 0; v < nvars; ++v )
5363 {
5366 lbinferinfos[v] = 0;
5367 ubinferinfos[v] = 0;
5368 }
5369
5370 /* collect earliest start times, latest completion time, and free energy contributions */
5371 collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5372
5373 /* sort the earliest start times and latest completion in non-decreasing order */
5374 SCIPsortIntInt(ests, permests, nvars);
5375 SCIPsortIntInt(lcts, permlcts, nvars);
5376
5377 /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5378 * points
5379 */
5380 computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5381
5382 /* propagate the upper bounds and "opportunistically" the lower bounds */
5383 SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5384 newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5385 permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5386
5387 /* propagate the lower bounds and "opportunistically" the upper bounds */
5388 SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5389 newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5390 permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5391
5392 /* apply the buffer bound changes */
5393 for( v = 0; v < nvars && !(*cutoff); ++v )
5394 {
5395 SCIP_Bool infeasible;
5396 SCIP_Bool tightened;
5397
5398 if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5399 {
5400 SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5401 TRUE, &infeasible, &tightened) );
5402 }
5403 else
5404 {
5405 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5406 }
5407
5408 /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5409 assert(!infeasible);
5410
5411 if( tightened )
5412 {
5413 (*nchgbds)++;
5414
5415 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5417 }
5418
5419 if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5420 {
5421 SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5422 TRUE, &infeasible, &tightened) );
5423 }
5424 else
5425 {
5426 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5427 }
5428
5429 /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5430 * bound update can be infeasible
5431 */
5432 if( infeasible )
5433 {
5434 /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5435 * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5436 * be analyzed in the case when begin and end exceed the 15 bit limit
5437 */
5439 {
5440 INFERINFO inferinfo;
5441 SCIP_VAR* var;
5442 int begin;
5443 int end;
5444
5445 var = vars[v];
5446 assert(var != NULL);
5447
5448 /* initialize conflict analysis */
5450
5451 /* convert int to inference information */
5452 inferinfo = intToInferInfo(ubinferinfos[v]);
5453
5454 /* collect time window from inference information */
5455 begin = inferInfoGetData1(inferinfo);
5456 end = inferInfoGetData2(inferinfo);
5457 assert(begin < end);
5458
5459 /* added to lower bound (which was undercut be new upper bound) of the variable */
5461
5462 /* analysis the upper bound change */
5463 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5464 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5465 conshdlrdata->usebdwidening, explanation) );
5466
5467 (*initialized) = TRUE;
5468 }
5469
5470 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5472
5473 (*cutoff) = TRUE;
5474 break;
5475 }
5476
5477 if( tightened )
5478 {
5479 (*nchgbds)++;
5480
5481 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5483 }
5484 }
5485
5486 SCIPfreeBufferArray(scip, &ubinferinfos);
5487 SCIPfreeBufferArray(scip, &lbinferinfos);
5488 SCIPfreeBufferArray(scip, &newubs);
5489 SCIPfreeBufferArray(scip, &newlbs);
5490
5491 /* free buffer arrays */
5492 SCIPfreeBufferArray(scip, &lsts);
5493 SCIPfreeBufferArray(scip, &ects);
5494 SCIPfreeBufferArray(scip, &ests);
5495 SCIPfreeBufferArray(scip, &lcts);
5496 SCIPfreeBufferArray(scip, &permests);
5497 SCIPfreeBufferArray(scip, &permlcts);
5498 SCIPfreeBufferArray(scip, &flexenergies);
5499 SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5500 SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5501
5502 return SCIP_OKAY;
5503}
5504
5505/** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5506 * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5507 * time table propagator
5508 */
5509static
5511 SCIP* scip, /**< SCIP data structure */
5512 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5513 SCIP_PROFILE* profile, /**< core profile */
5514 int nvars, /**< number of start time variables (activities) */
5515 SCIP_VAR** vars, /**< array of start time variables */
5516 int* durations, /**< array of durations */
5517 int* demands, /**< array of demands */
5518 int capacity, /**< cumulative capacity */
5519 int hmin, /**< left bound of time axis to be considered (including hmin) */
5520 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5521 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5522 int* nchgbds, /**< pointer to store the number of bound changes */
5523 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5524 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5525 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5526 )
5527{
5528 SCIP_Bool infeasible;
5529 int v;
5530
5531 assert(scip != NULL);
5532 assert(nvars > 0);
5533 assert(cons != NULL);
5534 assert(cutoff != NULL);
5535
5536 /* check if already a cutoff was detected */
5537 if( (*cutoff) )
5538 return SCIP_OKAY;
5539
5540 /* check if the time tabling should infer bounds */
5541 if( !conshdlrdata->ttinfer )
5542 return SCIP_OKAY;
5543
5544 assert(*initialized == FALSE);
5545
5546 SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5547 SCIPconsGetName(cons), hmin, hmax, capacity);
5548
5549 infeasible = FALSE;
5550
5551 /* if core profile is empty; nothing to do */
5552 if( SCIPprofileGetNTimepoints(profile) <= 1 )
5553 return SCIP_OKAY;
5554
5555 /* start checking each job whether the bounds can be improved */
5556 for( v = 0; v < nvars; ++v )
5557 {
5558 SCIP_VAR* var;
5559 int demand;
5560 int duration;
5561 int begin;
5562 int end;
5563 int est;
5564 int lst;
5565
5566 var = vars[v];
5567 assert(var != NULL);
5568
5569 duration = durations[v];
5570 assert(duration > 0);
5571
5572 /* collect earliest and latest start time */
5575
5576 /* check if the start time variables is already fixed; in that case we can ignore the job */
5577 if( est == lst )
5578 continue;
5579
5580 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5581 if( lst + duration <= hmin || est >= hmax )
5582 continue;
5583
5584 /* compute core interval w.r.t. effective time horizon */
5585 begin = MAX(hmin, lst);
5586 end = MIN(hmax, est + duration);
5587
5588 demand = demands[v];
5589 assert(demand > 0);
5590
5591 /* if the job has a core, remove it first */
5592 if( begin < end )
5593 {
5594 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5595 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5596
5597 SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5598 }
5599
5600 /* first try to update the earliest start time */
5601 SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5602 profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5603
5604 if( *cutoff )
5605 break;
5606
5607 /* second try to update the latest start time */
5608 SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5609 profile, v, nchgbds) );
5610
5611 if( *cutoff )
5612 break;
5613
5614 /* collect the potentially updated earliest and latest start time */
5617
5618 /* compute core interval w.r.t. effective time horizon */
5619 begin = MAX(hmin, lst);
5620 end = MIN(hmax, est + duration);
5621
5622 /* after updating the bound we might have a new core */
5623 if( begin < end )
5624 {
5625 int pos;
5626
5627 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5628 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5629
5630 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5631
5632 if( infeasible )
5633 {
5634 /* use conflict analysis to analysis the core insertion which was infeasible */
5635 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5636 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5637
5638 if( explanation != NULL )
5639 explanation[v] = TRUE;
5640
5641 (*cutoff) = TRUE;
5642
5643 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5645
5646 break;
5647 }
5648 }
5649 }
5650
5651 return SCIP_OKAY;
5652}
5653
5654
5655/** node data structure for the binary tree used for edgefinding (with overload checking) */
5656struct SCIP_NodeData
5657{
5658 SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5659 SCIP_Real key; /**< key which is to insert the corresponding search node */
5660 int est; /**< earliest start time if the node data belongs to a leaf */
5661 int lct; /**< latest completion time if the node data belongs to a leaf */
5662 int demand; /**< demand of the job if the node data belongs to a leaf */
5663 int duration; /**< duration of the job if the node data belongs to a leaf */
5664 int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5665 int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5666 SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5667 int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5668 int energylambda;
5669 SCIP_Longint enveloplambda;
5670 int idx; /**< index of the start time variable in the (global) variable array */
5671 SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5672};
5673typedef struct SCIP_NodeData SCIP_NODEDATA;
5674
5675
5676/** update node data structure starting from the given node along the path to the root node */
5677static
5679 SCIP* scip, /**< SCIP data structure */
5680 SCIP_BTNODE* node /**< search node which inserted */
5681 )
5682{
5683 SCIP_BTNODE* left;
5684 SCIP_BTNODE* right;
5686 SCIP_NODEDATA* leftdata;
5687 SCIP_NODEDATA* rightdata;
5688
5689 SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5690
5691 if( SCIPbtnodeIsLeaf(node) )
5692 node = SCIPbtnodeGetParent(node);
5693
5694 while( node != NULL )
5695 {
5696 /* get node data */
5698 assert(nodedata != NULL);
5699
5700 /* collect node data from left node */
5701 left = SCIPbtnodeGetLeftchild(node);
5702 assert(left != NULL);
5703 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5704 assert(leftdata != NULL);
5705
5706 /* collect node data from right node */
5707 right = SCIPbtnodeGetRightchild(node);
5708 assert(right != NULL);
5709 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5710 assert(rightdata != NULL);
5711
5712 /* update envelop and energy */
5713 if( leftdata->enveloptheta >= 0 )
5714 {
5715 assert(rightdata->energytheta != -1);
5716 nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5717 }
5718 else
5719 nodedata->enveloptheta = rightdata->enveloptheta;
5720
5721 assert(leftdata->energytheta != -1);
5722 assert(rightdata->energytheta != -1);
5723 nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5724
5725 if( leftdata->enveloplambda >= 0 )
5726 {
5727 assert(rightdata->energytheta != -1);
5728 nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5729 }
5730 else
5731 nodedata->enveloplambda = rightdata->enveloplambda;
5732
5733 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5734 nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5735
5736 SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5737
5738 if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5739 {
5740 assert(rightdata->energytheta != -1);
5741 assert(leftdata->energytheta != -1);
5742 nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5743 }
5744 else if( rightdata->energylambda >= 0 )
5745 {
5746 assert(leftdata->energytheta != -1);
5747 nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5748 }
5749 else if( leftdata->energylambda >= 0 )
5750 {
5751 assert(rightdata->energytheta != -1);
5752 nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5753 }
5754 else
5755 nodedata->energylambda = -1;
5756
5757 /* go to parent */
5758 node = SCIPbtnodeGetParent(node);
5759 }
5760
5761 SCIPdebugMsg(scip, "updating done\n");
5762}
5763
5764/** updates the key of the first parent on the trace which comes from left */
5765static
5767 SCIP_BTNODE* node, /**< node to start the trace */
5768 SCIP_Real key /**< update search key */
5769 )
5770{
5771 assert(node != NULL);
5772
5773 while( !SCIPbtnodeIsRoot(node) )
5774 {
5775 SCIP_BTNODE* parent;
5776
5777 parent = SCIPbtnodeGetParent(node);
5778 assert(parent != NULL);
5779
5780 if( SCIPbtnodeIsLeftchild(node) )
5781 {
5783
5785 assert(nodedata != NULL);
5786
5787 nodedata->key = key;
5788 return;
5789 }
5790
5791 node = parent;
5792 }
5793}
5794
5795
5796/** deletes the given node and updates all envelops */
5797static
5799 SCIP* scip, /**< SCIP data structure */
5800 SCIP_BT* tree, /**< binary tree */
5801 SCIP_BTNODE* node /**< node to be deleted */
5802 )
5803{
5804 SCIP_BTNODE* parent;
5805 SCIP_BTNODE* grandparent;
5806 SCIP_BTNODE* sibling;
5807
5808 assert(scip != NULL);
5809 assert(tree != NULL);
5810 assert(node != NULL);
5811
5812 assert(SCIPbtnodeIsLeaf(node));
5813 assert(!SCIPbtnodeIsRoot(node));
5814
5815 SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5816
5817 parent = SCIPbtnodeGetParent(node);
5818 assert(parent != NULL);
5819 if( SCIPbtnodeIsLeftchild(node) )
5820 {
5821 sibling = SCIPbtnodeGetRightchild(parent);
5823 }
5824 else
5825 {
5826 sibling = SCIPbtnodeGetLeftchild(parent);
5828 }
5829 assert(sibling != NULL);
5830
5831 grandparent = SCIPbtnodeGetParent(parent);
5832
5833 if( grandparent != NULL )
5834 {
5835 /* reset parent of sibling */
5836 SCIPbtnodeSetParent(sibling, grandparent);
5837
5838 /* reset child of grandparent to sibling */
5839 if( SCIPbtnodeIsLeftchild(parent) )
5840 {
5841 SCIPbtnodeSetLeftchild(grandparent, sibling);
5842 }
5843 else
5844 {
5846
5848 SCIPbtnodeSetRightchild(grandparent, sibling);
5849
5851
5852 updateKeyOnTrace(grandparent, nodedata->key);
5853 }
5854
5855 updateEnvelope(scip, grandparent);
5856 }
5857 else
5858 {
5859 SCIPbtnodeSetParent(sibling, NULL);
5860
5861 SCIPbtSetRoot(tree, sibling);
5862 }
5863
5864 SCIPbtnodeFree(tree, &parent);
5865
5866 return SCIP_OKAY;
5867}
5868
5869/** moves a node form the theta set into the lambda set and updates the envelops */
5870static
5872 SCIP* scip, /**< SCIP data structure */
5873 SCIP_BT* tree, /**< binary tree */
5874 SCIP_BTNODE* node /**< node to move into the lambda set */
5875 )
5876{
5878
5879 assert(scip != NULL);
5880 assert(tree != NULL);
5881 assert(node != NULL);
5882
5884 assert(nodedata != NULL);
5885 assert(nodedata->intheta);
5886
5887 /* move the contributions form the theta set into the lambda set */
5888 assert(nodedata->enveloptheta != -1);
5889 assert(nodedata->energytheta != -1);
5890 assert(nodedata->enveloplambda == -1);
5891 assert(nodedata->energylambda == -1);
5892 nodedata->enveloplambda = nodedata->enveloptheta;
5893 nodedata->energylambda = nodedata->energytheta;
5894
5895 nodedata->enveloptheta = -1;
5896 nodedata->energytheta = 0;
5897 nodedata->intheta = FALSE;
5898
5899 /* update the energy and envelop values on trace */
5900 updateEnvelope(scip, node);
5901
5902 return SCIP_OKAY;
5903}
5904
5905/** inserts a node into the theta set and update the envelops */
5906static
5908 SCIP* scip, /**< SCIP data structure */
5909 SCIP_BT* tree, /**< binary tree */
5910 SCIP_BTNODE* node, /**< node to insert */
5911 SCIP_NODEDATA* nodedatas, /**< array of node data */
5912 int* nodedataidx, /**< array of indices for node data */
5913 int* nnodedatas /**< pointer to number of node data */
5914 )
5915{
5916 /* if the tree is empty the node will be the root node */
5917 if( SCIPbtIsEmpty(tree) )
5918 {
5919 SCIPbtSetRoot(tree, node);
5920 }
5921 else
5922 {
5923 SCIP_NODEDATA* newnodedata;
5924 SCIP_NODEDATA* leafdata;
5926 SCIP_BTNODE* leaf;
5927 SCIP_BTNODE* newnode;
5928 SCIP_BTNODE* parent;
5929
5930 leaf = SCIPbtGetRoot(tree);
5931 assert(leaf != NULL);
5932
5933 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5934 assert(leafdata != NULL);
5935
5937 assert(nodedata != NULL);
5938 assert(nodedata->intheta);
5939
5940 /* find the position to insert the node */
5941 while( !SCIPbtnodeIsLeaf(leaf) )
5942 {
5943 if( nodedata->key < leafdata->key )
5944 leaf = SCIPbtnodeGetLeftchild(leaf);
5945 else
5946 leaf = SCIPbtnodeGetRightchild(leaf);
5947
5948 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5949 assert(leafdata != NULL);
5950 }
5951
5952 assert(leaf != NULL);
5953 assert(leaf != node);
5954
5955 /* store node data to be able to delete them latter */
5956 newnodedata = &nodedatas[*nnodedatas];
5957 nodedataidx[*nnodedatas] = *nnodedatas;
5958 ++(*nnodedatas);
5959
5960 /* init node data */
5961 newnodedata->var = NULL;
5962 newnodedata->key = SCIP_INVALID;
5963 newnodedata->est = INT_MIN;
5964 newnodedata->lct = INT_MAX;
5965 newnodedata->duration = 0;
5966 newnodedata->demand = 0;
5967 newnodedata->enveloptheta = -1;
5968 newnodedata->energytheta = 0;
5969 newnodedata->enveloplambda = -1;
5970 newnodedata->energylambda = -1;
5971 newnodedata->idx = -1;
5972 newnodedata->intheta = TRUE;
5973
5974 /* create a new node */
5975 SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
5976 assert(newnode != NULL);
5977
5978 parent = SCIPbtnodeGetParent(leaf);
5979
5980 if( parent != NULL )
5981 {
5982 SCIPbtnodeSetParent(newnode, parent);
5983
5984 /* check if the node is the left child */
5985 if( SCIPbtnodeGetLeftchild(parent) == leaf )
5986 {
5987 SCIPbtnodeSetLeftchild(parent, newnode);
5988 }
5989 else
5990 {
5991 SCIPbtnodeSetRightchild(parent, newnode);
5992 }
5993 }
5994 else
5995 SCIPbtSetRoot(tree, newnode);
5996
5997 if( nodedata->key < leafdata->key )
5998 {
5999 /* node is on the left */
6000 SCIPbtnodeSetLeftchild(newnode, node);
6001 SCIPbtnodeSetRightchild(newnode, leaf);
6002 newnodedata->key = nodedata->key;
6003 }
6004 else
6005 {
6006 /* leaf is on the left */
6007 SCIPbtnodeSetLeftchild(newnode, leaf);
6008 SCIPbtnodeSetRightchild(newnode, node);
6009 newnodedata->key = leafdata->key;
6010 }
6011
6012 SCIPbtnodeSetParent(leaf, newnode);
6013 SCIPbtnodeSetParent(node, newnode);
6014 }
6015
6016 /* update envelop */
6017 updateEnvelope(scip, node);
6018
6019 return SCIP_OKAY;
6020}
6021
6022/** returns the leaf responsible for the lambda energy */
6023static
6025 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6026 )
6027{
6028 SCIP_BTNODE* left;
6029 SCIP_BTNODE* right;
6031 SCIP_NODEDATA* leftdata;
6032 SCIP_NODEDATA* rightdata;
6033
6034 assert(node != NULL);
6035
6037 assert(nodedata != NULL);
6038
6039 /* check if the node is the (responsible) leaf */
6040 if( SCIPbtnodeIsLeaf(node) )
6041 {
6042 assert(!nodedata->intheta);
6043 return node;
6044 }
6045
6046 left = SCIPbtnodeGetLeftchild(node);
6047 assert(left != NULL);
6048
6049 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6050 assert(leftdata != NULL);
6051
6052 right = SCIPbtnodeGetRightchild(node);
6053 assert(right != NULL);
6054
6055 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6056 assert(rightdata != NULL);
6057
6058 assert(nodedata->energylambda != -1);
6059 assert(rightdata->energytheta != -1);
6060
6061 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6063
6064 assert(leftdata->energytheta != -1);
6065 assert(rightdata->energylambda != -1);
6066 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6067
6069}
6070
6071/** returns the leaf responsible for the lambda envelop */
6072static
6074 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6075 )
6076{
6077 SCIP_BTNODE* left;
6078 SCIP_BTNODE* right;
6080 SCIP_NODEDATA* leftdata;
6081 SCIP_NODEDATA* rightdata;
6082
6083 assert(node != NULL);
6084
6086 assert(nodedata != NULL);
6087
6088 /* check if the node is the (responsible) leaf */
6089 if( SCIPbtnodeIsLeaf(node) )
6090 {
6091 assert(!nodedata->intheta);
6092 return node;
6093 }
6094
6095 left = SCIPbtnodeGetLeftchild(node);
6096 assert(left != NULL);
6097
6098 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6099 assert(leftdata != NULL);
6100
6101 right = SCIPbtnodeGetRightchild(node);
6102 assert(right != NULL);
6103
6104 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6105 assert(rightdata != NULL);
6106
6107 assert(nodedata->enveloplambda != -1);
6108 assert(rightdata->energytheta != -1);
6109
6110 /* check if the left or right child is the one defining the envelop for the lambda set */
6111 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6113 else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6114 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6116
6117 assert(rightdata->enveloplambda != -1);
6118 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6119
6121}
6122
6123
6124/** reports all elements from set theta to generate a conflicting set */
6125static
6127 SCIP_BTNODE* node, /**< node within a theta subtree */
6128 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6129 int* nelements, /**< pointer to store the number of elements in omegaset */
6130 int* est, /**< pointer to store the earliest start time of the omega set */
6131 int* lct, /**< pointer to store the latest start time of the omega set */
6132 int* energy /**< pointer to store the energy of the omega set */
6133 )
6134{
6136
6138 assert(nodedata != NULL);
6139
6140 if( !SCIPbtnodeIsLeaf(node) )
6141 {
6142 collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6143 collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6144 }
6145 else if( nodedata->intheta )
6146 {
6147 assert(nodedata->var != NULL);
6148 SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6149
6150 omegaset[*nelements] = node;
6151 (*est) = MIN(*est, nodedata->est);
6152 (*lct) = MAX(*lct, nodedata->lct);
6153 (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6154 (*nelements)++;
6155 }
6156}
6157
6158
6159/** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6160static
6162 SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6163 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6164 int* nelements, /**< pointer to store the number of elements in omegaset */
6165 int* est, /**< pointer to store the earliest start time of the omega set */
6166 int* lct, /**< pointer to store the latest start time of the omega set */
6167 int* energy /**< pointer to store the energy of the omega set */
6168 )
6169{
6170 assert(node != NULL);
6171
6172 if( SCIPbtnodeIsLeaf(node) )
6173 {
6174 collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6175 }
6176 else
6177 {
6178 SCIP_BTNODE* left;
6179 SCIP_BTNODE* right;
6181 SCIP_NODEDATA* leftdata;
6182 SCIP_NODEDATA* rightdata;
6183
6185 assert(nodedata != NULL);
6186
6187 left = SCIPbtnodeGetLeftchild(node);
6188 assert(left != NULL);
6189
6190 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6191 assert(leftdata != NULL);
6192
6193 right = SCIPbtnodeGetRightchild(node);
6194 assert(right != NULL);
6195
6196 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6197 assert(rightdata != NULL);
6198
6200 assert(nodedata != NULL);
6201
6202 assert(nodedata->enveloptheta != -1);
6203 assert(rightdata->energytheta != -1);
6204
6205 if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6206 {
6207 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6208 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6209 }
6210 else
6211 {
6212 assert(rightdata->enveloptheta != -1);
6213 assert(nodedata->enveloptheta == rightdata->enveloptheta);
6214 traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6215 }
6216 }
6217}
6218
6219/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6220static
6222 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6223 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6224 int* nelements, /**< pointer to store the number of elements in omega set */
6225 int* est, /**< pointer to store the earliest start time of the omega set */
6226 int* lct, /**< pointer to store the latest start time of the omega set */
6227 int* energy /**< pointer to store the energy of the omega set */
6228 )
6229{
6230 SCIP_BTNODE* left;
6231 SCIP_BTNODE* right;
6233 SCIP_NODEDATA* leftdata;
6234 SCIP_NODEDATA* rightdata;
6235
6236 assert(node != NULL);
6237
6239 assert(nodedata != NULL);
6240
6241 /* check if the node is a leaf */
6242 if( SCIPbtnodeIsLeaf(node) )
6243 return;
6244
6245 left = SCIPbtnodeGetLeftchild(node);
6246 assert(left != NULL);
6247
6248 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6249 assert(leftdata != NULL);
6250
6251 right = SCIPbtnodeGetRightchild(node);
6252 assert(right != NULL);
6253
6254 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6255 assert(rightdata != NULL);
6256
6257 assert(nodedata->energylambda != -1);
6258 assert(rightdata->energytheta != -1);
6259
6260 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6261 {
6262 traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6263 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6264 }
6265 else
6266 {
6267 assert(leftdata->energytheta != -1);
6268 assert(rightdata->energylambda != -1);
6269 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6270
6271 collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6272 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6273 }
6274}
6275
6276/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6277static
6279 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6280 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6281 int* nelements, /**< pointer to store the number of elements in omega set */
6282 int* est, /**< pointer to store the earliest start time of the omega set */
6283 int* lct, /**< pointer to store the latest start time of the omega set */
6284 int* energy /**< pointer to store the energy of the omega set */
6285 )
6286{
6287 SCIP_BTNODE* left;
6288 SCIP_BTNODE* right;
6290 SCIP_NODEDATA* leftdata;
6291 SCIP_NODEDATA* rightdata;
6292
6293 assert(node != NULL);
6294
6296 assert(nodedata != NULL);
6297
6298 /* check if the node is a leaf */
6299 if( SCIPbtnodeIsLeaf(node) )
6300 {
6301 assert(!nodedata->intheta);
6302 return;
6303 }
6304
6305 left = SCIPbtnodeGetLeftchild(node);
6306 assert(left != NULL);
6307
6308 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6309 assert(leftdata != NULL);
6310
6311 right = SCIPbtnodeGetRightchild(node);
6312 assert(right != NULL);
6313
6314 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6315 assert(rightdata != NULL);
6316
6317 assert(nodedata->enveloplambda != -1);
6318 assert(rightdata->energytheta != -1);
6319
6320 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6321 {
6322 traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6323 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6324 }
6325 else
6326 {
6327 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6328 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6329 {
6330 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6331 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6332 }
6333 else
6334 {
6335 assert(rightdata->enveloplambda != -1);
6336 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6337 traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6338 }
6339 }
6340}
6341
6342/** compute the energy contribution by job which corresponds to the given leaf */
6343static
6345 SCIP_BTNODE* node /**< leaf */
6346 )
6347{
6349 int duration;
6350
6352 assert(nodedata != NULL);
6353 assert(nodedata->var != NULL);
6354
6355 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6356 assert(duration > 0);
6357
6358 SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6360 SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6361
6362 /* return energy which is contributed by the start time variable */
6363 return nodedata->demand * duration;
6364}
6365
6366/** comparison method for two node data w.r.t. the earliest start time */
6367static
6369{
6370 int est1;
6371 int est2;
6372
6373 est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6374 est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6375
6376 return (est1 - est2);
6377}
6378
6379/** comparison method for two node data w.r.t. the latest completion time */
6380static
6382{
6383 SCIP_NODEDATA* nodedatas;
6384
6385 nodedatas = (SCIP_NODEDATA*) dataptr;
6386 return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6387}
6388
6389
6390/** an overload was detected; initialized conflict analysis, add an initial reason
6391 *
6392 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6393 */
6394static
6396 SCIP* scip, /**< SCIP data structure */
6397 SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6398 int capacity, /**< cumulative capacity */
6399 int nleaves, /**< number of responsible leaves */
6400 int est, /**< earliest start time of the ...... */
6401 int lct, /**< latest completly time of the .... */
6402 int reportedenergy, /**< energy which already reported */
6403 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6404 int shift, /**< shift applied to all jobs before adding them to the tree */
6405 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6406 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6407 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6408 )
6409{
6410 SCIP_Longint energy;
6411 int j;
6412
6413 /* do nothing if conflict analysis is not applicable */
6415 return SCIP_OKAY;
6416
6417 SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6418
6419 /* compute energy of initial time window */
6420 energy = ((SCIP_Longint) lct - est) * capacity;
6421
6422 /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6423 SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6424
6425 /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6426 * thereby, compute the time window of interest
6427 */
6428 for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6429 {
6431
6433 assert(nodedata != NULL);
6434
6435 reportedenergy += computeEnergyContribution(leaves[j]);
6436
6437 /* adjust energy if the earliest start time decrease */
6438 if( nodedata->est < est )
6439 {
6440 est = nodedata->est;
6441 energy = ((SCIP_Longint) lct - est) * capacity;
6442 }
6443 }
6444 assert(reportedenergy > energy);
6445
6446 SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6447
6448 /* initialize conflict analysis */
6450
6451 /* flip earliest start time and latest completion time */
6452 if( !propest )
6453 {
6454 SCIPswapInts(&est, &lct);
6455
6456 /* shift earliest start time and latest completion time */
6457 lct = shift - lct;
6458 est = shift - est;
6459 }
6460 else
6461 {
6462 /* shift earliest start time and latest completion time */
6463 lct = lct + shift;
6464 est = est + shift;
6465 }
6466
6467 nleaves = j;
6468
6469 /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6470 * overloaded
6471 */
6472 for( j = nleaves-1; j >= 0; --j )
6473 {
6475
6477 assert(nodedata != NULL);
6478 assert(nodedata->var != NULL);
6479
6480 /* check if bound widening should be used */
6481 if( usebdwidening )
6482 {
6483 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6484 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6485 }
6486 else
6487 {
6490 }
6491
6492 if( explanation != NULL )
6493 explanation[nodedata->idx] = TRUE;
6494 }
6495
6496 (*initialized) = TRUE;
6497
6498 return SCIP_OKAY;
6499}
6500
6501/** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6502 * responsible interval bounds in *est_omega and *lct_omega
6503 */
6504static
6506 SCIP* scip, /**< SCIP data structure */
6507 int duration, /**< duration of the job to move */
6508 int demand, /**< demand of the job to move */
6509 int capacity, /**< cumulative capacity */
6510 int est, /**< earliest start time of the omega set */
6511 int lct, /**< latest start time of the omega set */
6512 int energy /**< energy of the omega set */
6513 )
6514{
6515 int newest;
6516
6517 newest = 0;
6518
6519 assert(scip != NULL);
6520
6521 if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6522 {
6523 if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6524 {
6525 newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6526 newest += est;
6527 }
6528 }
6529
6530 return newest;
6531}
6532
6533/** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6534 *
6535 * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6536 * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6537 */
6538static
6540 SCIP* scip, /**< SCIP data structure */
6541 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6542 SCIP_CONS* cons, /**< constraint which is propagated */
6543 SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6544 SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6545 int capacity, /**< cumulative capacity */
6546 int ncands, /**< number of candidates */
6547 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6548 int shift, /**< shift applied to all jobs before adding them to the tree */
6549 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6550 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6551 int* nchgbds, /**< pointer to store the number of bound changes */
6552 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6553 )
6554{
6555 SCIP_NODEDATA* rootdata;
6556 int j;
6557
6558 assert(!SCIPbtIsEmpty(tree));
6559
6560 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6561 assert(rootdata != NULL);
6562
6563 /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6564 for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6565 {
6567
6568 if( SCIPbtnodeIsRoot(leaves[j]) )
6569 break;
6570
6572 assert(nodedata->est != -1);
6573
6574 /* check if the root lambda envelop exeeds the available capacity */
6575 while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6576 {
6577 SCIP_BTNODE** omegaset;
6578 SCIP_BTNODE* leaf;
6579 SCIP_NODEDATA* leafdata;
6580 int nelements;
6581 int energy;
6582 int newest;
6583 int est;
6584 int lct;
6585
6586 assert(!(*cutoff));
6587
6588 /* find responsible leaf for the lambda envelope */
6590 assert(leaf != NULL);
6591 assert(SCIPbtnodeIsLeaf(leaf));
6592
6593 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6594 assert(leafdata != NULL);
6595 assert(!leafdata->intheta);
6596 assert(leafdata->duration > 0);
6597 assert(leafdata->est >= 0);
6598
6599 /* check if the job has to be removed since its latest completion is to large */
6600 if( leafdata->est + leafdata->duration >= nodedata->lct )
6601 {
6602 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6603
6604 /* the root might changed therefore we need to collect the new root node data */
6605 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6606 assert(rootdata != NULL);
6607
6608 continue;
6609 }
6610
6611 /* compute omega set */
6612 SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6613
6614 nelements = 0;
6615 est = INT_MAX;
6616 lct = INT_MIN;
6617 energy = 0;
6618
6619 /* collect the omega set from theta set */
6620 traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6621 assert(nelements > 0);
6622 assert(nelements < ncands);
6623
6624 newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6625
6626 /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6627 if( newest > lct )
6628 {
6629 SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6630
6631 /* analyze over load */
6632 SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6633 conshdlrdata->usebdwidening, initialized, explanation) );
6634 (*cutoff) = TRUE;
6635
6636 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6638 }
6639 else if( newest > 0 )
6640 {
6641 SCIP_Bool infeasible;
6642 SCIP_Bool tightened;
6643 INFERINFO inferinfo;
6644
6645 if( propest )
6646 {
6647 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6648 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6649
6650 SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6651 SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6652
6653 if( inferInfoIsValid(inferinfo) )
6654 {
6655 SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6656 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6657 }
6658 else
6659 {
6660 SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6661 TRUE, &infeasible, &tightened) );
6662 }
6663
6664 /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6666 }
6667 else
6668 {
6669 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6670 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6671
6672 SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6673 SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6674
6675 if( inferInfoIsValid(inferinfo) )
6676 {
6677 SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6678 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6679 }
6680 else
6681 {
6682 SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6683 TRUE, &infeasible, &tightened) );
6684 }
6685
6686 /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6688 }
6689
6690 /* adjust the earliest start time */
6691 if( tightened )
6692 {
6693 leafdata->est = newest;
6694 (*nchgbds)++;
6695 }
6696
6697 if( infeasible )
6698 {
6699 /* initialize conflict analysis if conflict analysis is applicable */
6701 {
6702 int i;
6703
6704 SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6705
6707
6708 /* add lower and upper bound of variable which leads to the infeasibilty */
6709 SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6710 SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6711
6712 if( explanation != NULL )
6713 explanation[leafdata->idx] = TRUE;
6714
6715 /* add lower and upper bound of variable which lead to the infeasibilty */
6716 for( i = 0; i < nelements; ++i )
6717 {
6719 assert(nodedata != NULL);
6720
6723
6724 if( explanation != NULL )
6725 explanation[nodedata->idx] = TRUE;
6726 }
6727
6728 (*initialized) = TRUE;
6729 }
6730
6731 (*cutoff) = TRUE;
6732
6733 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6735 }
6736 }
6737
6738 /* free omegaset array */
6739 SCIPfreeBufferArray(scip, &omegaset);
6740
6741 /* delete responsible leaf from lambda */
6742 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6743
6744 /* the root might changed therefore we need to collect the new root node data */
6745 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6746 assert(rootdata != NULL);
6747 }
6748
6749 /* move current job j from the theta set into the lambda set */
6750 SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6751 }
6752
6753 return SCIP_OKAY;
6754}
6755
6756/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6757 *
6758 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6759 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6760 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6761 */
6762static
6764 SCIP* scip, /**< SCIP data structure */
6765 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6766 int nvars, /**< number of start time variables (activities) */
6767 SCIP_VAR** vars, /**< array of start time variables */
6768 int* durations, /**< array of durations */
6769 int* demands, /**< array of demands */
6770 int capacity, /**< cumulative capacity */
6771 int hmin, /**< left bound of time axis to be considered (including hmin) */
6772 int hmax, /**< right bound of time axis to be considered (not including hmax) */
6773 SCIP_CONS* cons, /**< constraint which is propagated */
6774 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6775 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6776 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6777 int* nchgbds, /**< pointer to store the number of bound changes */
6778 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6779 )
6780{
6781 SCIP_NODEDATA* nodedatas;
6782 SCIP_BTNODE** leaves;
6783 SCIP_BT* tree;
6784 int* nodedataidx;
6785
6786 int totalenergy;
6787 int nnodedatas;
6788 int ninsertcands;
6789 int ncands;
6790
6791 int shift;
6792 int idx = -1;
6793 int j;
6794
6795 assert(scip != NULL);
6796 assert(cons != NULL);
6797 assert(initialized != NULL);
6798 assert(cutoff != NULL);
6799 assert(*cutoff == FALSE);
6800
6801 SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6802
6803 SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6804 SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6806
6807 ncands = 0;
6808 totalenergy = 0;
6809
6811
6812 /* compute the shift which we apply to compute .... latest completion time of all jobs */
6813 if( propest )
6814 shift = 0;
6815 else
6816 {
6817 shift = 0;
6818
6819 /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6820 * earliest start time propagation to handle the latest completion times
6821 */
6822 for( j = 0; j < nvars; ++j )
6823 {
6824 int lct;
6825
6826 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6827 shift = MAX(shift, lct);
6828 }
6829 }
6830
6831 /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6832 * horizon
6833 */
6834 for( j = 0; j < nvars; ++j )
6835 {
6837 SCIP_VAR* var;
6838 int duration;
6839 int leftadjust;
6840 int rightadjust;
6841 int energy;
6842 int est;
6843 int lct;
6844
6845 var = vars[j];
6846 assert(var != NULL);
6847
6848 duration = durations[j];
6849 assert(duration > 0);
6850
6851 leftadjust = 0;
6852 rightadjust = 0;
6853
6856
6857 /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6858 * effective horizon [hmin,hmax)
6859 */
6860 if( conshdlrdata->useadjustedjobs )
6861 {
6862 if( est < hmin )
6863 {
6864 leftadjust = (hmin - est);
6865 est = hmin;
6866 }
6867 if( lct > hmax )
6868 {
6869 rightadjust = (lct - hmax);
6870 lct = hmax;
6871 }
6872
6873 /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6874 * with the effective time horizon
6875 */
6876 if( duration - leftadjust - rightadjust <= 0 )
6877 continue;
6878 }
6879 else if( est < hmin || lct > hmax )
6880 continue;
6881
6882 energy = demands[j] * (duration - leftadjust - rightadjust);
6883 assert(energy > 0);
6884
6885 totalenergy += energy;
6886
6887 /* flip earliest start time and latest completion time */
6888 if( !propest )
6889 {
6890 SCIPswapInts(&est, &lct);
6891
6892 /* shift earliest start time and latest completion time */
6893 lct = shift - lct;
6894 est = shift - est;
6895 }
6896 else
6897 {
6898 /* shift earliest start time and latest completion time */
6899 lct = lct - shift;
6900 est = est - shift;
6901 }
6902 assert(est < lct);
6903 assert(est >= 0);
6904 assert(lct >= 0);
6905
6906 /* create search node data */
6907 nodedata = &nodedatas[ncands];
6908 nodedataidx[ncands] = ncands;
6909 ++ncands;
6910
6911 /* initialize search node data */
6912 /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6913 nodedata->key = est + j / (2.0 * nvars);
6914 nodedata->var = var;
6915 nodedata->est = est;
6916 nodedata->lct = lct;
6917 nodedata->demand = demands[j];
6918 nodedata->duration = duration;
6919 nodedata->leftadjust = leftadjust;
6920 nodedata->rightadjust = rightadjust;
6921
6922 /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6923 * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6924 * particular time interval [a,b] against the time interval [0,b].
6925 */
6926 nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
6927 nodedata->energytheta = energy;
6928 nodedata->enveloplambda = -1;
6929 nodedata->energylambda = -1;
6930
6931 nodedata->idx = j;
6932 nodedata->intheta = TRUE;
6933 }
6934
6935 nnodedatas = ncands;
6936
6937 /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6938 SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
6939
6940 ninsertcands = 0;
6941
6942 /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6943 * the root envelop detects an overload
6944 */
6945 for( j = 0; j < ncands; ++j )
6946 {
6947 SCIP_BTNODE* leaf;
6948 SCIP_NODEDATA* rootdata;
6949
6950 idx = nodedataidx[j];
6951
6952 /* check if the new job opens a time window which size is so large that it offers more energy than the total
6953 * energy of all candidate jobs. If so we skip that one.
6954 */
6955 if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
6956 {
6957 /* set the earliest start time to minus one to mark that candidate to be not used */
6958 nodedatas[idx].est = -1;
6959 continue;
6960 }
6961
6962 /* create search node */
6963 SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
6964
6965 /* insert new node into the theta set and updete the envelops */
6966 SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
6967 assert(nnodedatas <= 2*nvars);
6968
6969 /* move the inserted candidates together */
6970 leaves[ninsertcands] = leaf;
6971 ninsertcands++;
6972
6973 assert(!SCIPbtIsEmpty(tree));
6974 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6975 assert(rootdata != NULL);
6976
6977 /* check if the theta set envelops exceeds the available capacity */
6978 if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
6979 {
6980 SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
6981 (*cutoff) = TRUE;
6982
6983 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6985
6986 break;
6987 }
6988 }
6989
6990 /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
6991 if( *cutoff )
6992 {
6993 int glbenery;
6994 int est;
6995 int lct;
6996
6997 glbenery = 0;
6998 assert( 0 <= idx );
6999 est = nodedatas[idx].est;
7000 lct = nodedatas[idx].lct;
7001
7002 /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7003 * which led to an overload
7004 */
7005 for( j = j+1; j < ncands; ++j )
7006 {
7008 int duration;
7009 int glbest;
7010 int glblct;
7011
7012 idx = nodedataidx[j];
7013 nodedata = &nodedatas[idx];
7014 assert(nodedata != NULL);
7015
7016 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7017
7018 /* get latest start time */
7020 glblct = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7021
7022 /* check if parts of the jobs run with the time window defined by the last inserted job */
7023 if( glbest < est )
7024 duration -= (est - glbest);
7025
7026 if( glblct > lct )
7027 duration -= (glblct - lct);
7028
7029 if( duration > 0 )
7030 {
7031 glbenery += nodedata->demand * duration;
7032
7033 if( explanation != NULL )
7034 explanation[nodedata->idx] = TRUE;
7035 }
7036 }
7037
7038 /* analyze the overload */
7039 SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7040 conshdlrdata->usebdwidening, initialized, explanation) );
7041 }
7042 else if( ninsertcands > 1 && conshdlrdata->efinfer )
7043 {
7044 /* if we have more than one job insterted and edge-finding should be performed we do it */
7045 SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7046 propest, shift, initialized, explanation, nchgbds, cutoff) );
7047 }
7048
7049 /* free theta tree */
7050 SCIPbtFree(&tree);
7051
7052 /* free buffer arrays */
7053 SCIPfreeBufferArray(scip, &leaves);
7054 SCIPfreeBufferArray(scip, &nodedataidx);
7055 SCIPfreeBufferArray(scip, &nodedatas);
7056
7057 return SCIP_OKAY;
7058}
7059
7060/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7061 *
7062 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7063 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7064 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7065 */
7066static
7068 SCIP* scip, /**< SCIP data structure */
7069 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7070 int nvars, /**< number of start time variables (activities) */
7071 SCIP_VAR** vars, /**< array of start time variables */
7072 int* durations, /**< array of durations */
7073 int* demands, /**< array of demands */
7074 int capacity, /**< cumulative capacity */
7075 int hmin, /**< left bound of time axis to be considered (including hmin) */
7076 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7077 SCIP_CONS* cons, /**< constraint which is propagated */
7078 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7079 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7080 int* nchgbds, /**< pointer to store the number of bound changes */
7081 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7082 )
7083{
7084 /* check if a cutoff was already detected */
7085 if( (*cutoff) )
7086 return SCIP_OKAY;
7087
7088 /* check if at least the basic overload checking should be preformed */
7089 if( !conshdlrdata->efcheck )
7090 return SCIP_OKAY;
7091
7092 /* check for overload, which may result in a cutoff */
7093 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7094 cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7095
7096 /* check if a cutoff was detected */
7097 if( (*cutoff) )
7098 return SCIP_OKAY;
7099
7100 /* check if bound should be infer */
7101 if( !conshdlrdata->efinfer )
7102 return SCIP_OKAY;
7103
7104 /* check for overload, which may result in a cutoff */
7105 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7106 cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7107
7108 return SCIP_OKAY;
7109}
7110
7111/** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7112 * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7113 * event points
7114 */
7115static
7117 SCIP* scip, /**< SCIP data structure */
7118 int nvars, /**< number of start time variables (activities) */
7119 SCIP_VAR** vars, /**< array of start time variables */
7120 int* durations, /**< array of durations */
7121 int* demands, /**< array of demands */
7122 int capacity, /**< cumulative capacity */
7123 int hmin, /**< left bound of time axis to be considered (including hmin) */
7124 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7125 SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7126 )
7127{
7128 SCIP_VAR* var;
7129 int* starttimes; /* stores when each job is starting */
7130 int* endtimes; /* stores when each job ends */
7131 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7132 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7133
7134 int lb;
7135 int ub;
7136 int freecapacity; /* remaining capacity */
7137 int curtime; /* point in time which we are just checking */
7138 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7139 int njobs;
7140 int j;
7141
7142 assert(scip != NULL);
7143 assert(redundant != NULL);
7144
7145 (*redundant) = TRUE;
7146
7147 /* if no activities are associated with this cumulative then this constraint is redundant */
7148 if( nvars == 0 )
7149 return SCIP_OKAY;
7150
7151 assert(vars != NULL);
7152
7153 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7154 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7155 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7156 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7157
7158 njobs = 0;
7159
7160 /* assign variables, start and endpoints to arrays */
7161 for( j = 0; j < nvars; ++j )
7162 {
7163 assert(durations[j] > 0);
7164 assert(demands[j] > 0);
7165
7166 var = vars[j];
7167 assert(var != NULL);
7168
7171
7172 /* check if jobs runs completely outside of the effective time horizon */
7173 if( lb >= hmax || ub <= hmin - durations[j] )
7174 continue;
7175
7176 starttimes[njobs] = MAX(lb, hmin);
7177 startindices[njobs] = j;
7178
7179 endtimes[njobs] = MIN(ub == INT_MAX ? ub : ub + durations[j], hmax);
7180 endindices[njobs] = j;
7181 assert(starttimes[njobs] <= endtimes[njobs]);
7182 njobs++;
7183 }
7184
7185 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7186 SCIPsortIntInt(starttimes, startindices, njobs);
7187 SCIPsortIntInt(endtimes, endindices, njobs);
7188
7189 endindex = 0;
7190 freecapacity = capacity;
7191
7192 /* check each start point of a job whether the capacity is violated or not */
7193 for( j = 0; j < njobs; ++j )
7194 {
7195 curtime = starttimes[j];
7196
7197 /* stop checking, if time point is above hmax */
7198 if( curtime >= hmax )
7199 break;
7200
7201 /* subtract all capacity needed up to this point */
7202 freecapacity -= demands[startindices[j]];
7203 while( j+1 < njobs && starttimes[j+1] == curtime )
7204 {
7205 ++j;
7206 freecapacity -= demands[startindices[j]];
7207 }
7208
7209 /* free all capacity usages of jobs the are no longer running */
7210 while( endtimes[endindex] <= curtime )
7211 {
7212 freecapacity += demands[endindices[endindex]];
7213 ++endindex;
7214 }
7215 assert(freecapacity <= capacity);
7216
7217 /* check freecapacity to be smaller than zero */
7218 if( freecapacity < 0 && curtime >= hmin )
7219 {
7220 (*redundant) = FALSE;
7221 break;
7222 }
7223 } /*lint --e{850}*/
7224
7225 /* free all buffer arrays */
7226 SCIPfreeBufferArray(scip, &endindices);
7227 SCIPfreeBufferArray(scip, &startindices);
7228 SCIPfreeBufferArray(scip, &endtimes);
7229 SCIPfreeBufferArray(scip, &starttimes);
7230
7231 return SCIP_OKAY;
7232}
7233
7234/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7235 * completion time
7236 */
7237static
7239 SCIP* scip, /**< SCIP data structure */
7240 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7241 SCIP_PROFILE* profile, /**< resource profile */
7242 int nvars, /**< number of variables (jobs) */
7243 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7244 int* durations, /**< array containing corresponding durations */
7245 int* demands, /**< array containing corresponding demands */
7246 int capacity, /**< cumulative capacity */
7247 int hmin, /**< left bound of time axis to be considered (including hmin) */
7248 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7249 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7250 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7251 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7252 )
7253{
7254 int v;
7255
7256 /* insert all cores */
7257 for( v = 0; v < nvars; ++v )
7258 {
7259 SCIP_VAR* var;
7260 SCIP_Bool infeasible;
7261 int duration;
7262 int demand;
7263 int begin;
7264 int end;
7265 int est;
7266 int lst;
7267 int pos;
7268
7269 var = vars[v];
7270 assert(var != NULL);
7273
7274 duration = durations[v];
7275 assert(duration > 0);
7276
7277 demand = demands[v];
7278 assert(demand > 0);
7279
7280 /* collect earliest and latest start time */
7283
7284 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7285 if( lst + duration <= hmin || est >= hmax )
7286 continue;
7287
7288 /* compute core interval w.r.t. effective time horizon */
7289 begin = MAX(hmin, lst);
7290 end = MIN(hmax, est + duration);
7291
7292 /* check if a core exists */
7293 if( begin >= end )
7294 continue;
7295
7296 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7297 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7298
7299 /* insert the core into core resource profile (complexity O(log n)) */
7300 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7301
7302 /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7303 if( infeasible )
7304 {
7305 assert(begin <= SCIPprofileGetTime(profile, pos));
7306 assert(end > SCIPprofileGetTime(profile, pos));
7307
7308 /* use conflict analysis to analysis the core insertion which was infeasible */
7309 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7310 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7311
7312 if( explanation != NULL )
7313 explanation[v] = TRUE;
7314
7315 (*cutoff) = TRUE;
7316
7317 /* for the statistic we count the number of times a cutoff was detected due the time-time */
7319
7320 break;
7321 }
7322 }
7323
7324 return SCIP_OKAY;
7325}
7326
7327/** propagate the cumulative condition */
7328static
7330 SCIP* scip, /**< SCIP data structure */
7331 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7332 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7333 int nvars, /**< number of start time variables (activities) */
7334 SCIP_VAR** vars, /**< array of start time variables */
7335 int* durations, /**< array of durations */
7336 int* demands, /**< array of demands */
7337 int capacity, /**< cumulative capacity */
7338 int hmin, /**< left bound of time axis to be considered (including hmin) */
7339 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7340 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7341 int* nchgbds, /**< pointer to store the number of bound changes */
7342 SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7343 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7344 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7345 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7346 )
7347{
7348 SCIP_PROFILE* profile;
7349
7350 SCIP_RETCODE retcode = SCIP_OKAY;
7351
7352 assert(nchgbds != NULL);
7353 assert(initialized != NULL);
7354 assert(cutoff != NULL);
7355 assert(!(*cutoff));
7356
7357 /**@todo avoid always sorting the variable array */
7358
7359 /* check if the constraint is redundant */
7360 SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7361
7362 if( *redundant )
7363 return SCIP_OKAY;
7364
7365 /* create an empty resource profile for profiling the cores of the jobs */
7366 SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7367
7368 /* create core profile (compulsory parts) */
7369 SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7370 initialized, explanation, cutoff), TERMINATE );
7371
7372 /* propagate the job cores until nothing else can be detected */
7373 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7374 {
7375 SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7376 nchgbds, initialized, explanation, cutoff), TERMINATE );
7377 }
7378
7379 /* run edge finding propagator */
7380 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7381 {
7382 SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7383 cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7384 }
7385
7386 /* run time-table edge-finding propagator */
7387 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7388 {
7389 SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7390 nchgbds, initialized, explanation, cutoff), TERMINATE );
7391 }
7392 /* free resource profile */
7393TERMINATE:
7394 SCIPprofileFree(&profile);
7395
7396 return retcode;
7397}
7398
7399/** propagate the cumulative constraint */
7400static
7402 SCIP* scip, /**< SCIP data structure */
7403 SCIP_CONS* cons, /**< constraint to propagate */
7404 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7405 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7406 int* nchgbds, /**< pointer to store the number of bound changes */
7407 int* ndelconss, /**< pointer to store the number of deleted constraints */
7408 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7409 )
7410{
7411 SCIP_CONSDATA* consdata;
7412 SCIP_Bool initialized;
7413 SCIP_Bool redundant;
7414 int oldnchgbds;
7415
7416 assert(scip != NULL);
7417 assert(cons != NULL);
7418
7419 consdata = SCIPconsGetData(cons);
7420 assert(consdata != NULL);
7421
7422 oldnchgbds = *nchgbds;
7423 initialized = FALSE;
7424 redundant = FALSE;
7425
7426 if( SCIPconsIsDeleted(cons) )
7427 {
7429 return SCIP_OKAY;
7430 }
7431
7432 /* if the constraint marked to be propagated, do nothing */
7433 if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7434 return SCIP_OKAY;
7435
7436 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7437 consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7438 consdata->hmin, consdata->hmax, cons,
7439 nchgbds, &redundant, &initialized, NULL, cutoff) );
7440
7441 if( redundant )
7442 {
7443 SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7444 SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7445
7446 if( !SCIPinProbing(scip) )
7447 {
7449 (*ndelconss)++;
7450 }
7451 }
7452 else
7453 {
7454 if( initialized )
7455 {
7456 /* run conflict analysis since it was initialized */
7457 assert(*cutoff == TRUE);
7458 SCIPdebugMsg(scip, "start conflict analysis\n");
7460 }
7461
7462 /* if successful, reset age of constraint */
7463 if( *cutoff || *nchgbds > oldnchgbds )
7464 {
7466 }
7467 else
7468 {
7469 /* mark the constraint to be propagated */
7470 consdata->propagated = TRUE;
7471 }
7472 }
7473
7474 return SCIP_OKAY;
7475}
7476
7477/** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7478 * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7479 * be realize as domain reduction. Otherwise we do nothing
7480 */
7481static
7483 SCIP* scip, /**< SCIP data structure */
7484 SCIP_VAR** vars, /**< problem variables */
7485 int nvars, /**< number of problem variables */
7486 int probingpos, /**< variable number to apply probing on */
7487 SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7488 SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7489 SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7490 SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7491 SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7492 SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7493 SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7494 SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7495 SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7496 SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7497 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7498 SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7499 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7500 )
7501{
7502 SCIP_VAR* var;
7503 SCIP_Bool tightened;
7504
7505 assert(probingpos >= 0);
7506 assert(probingpos < nvars);
7507 assert(success != NULL);
7508 assert(cutoff != NULL);
7509
7510 var = vars[probingpos];
7511 assert(var != NULL);
7516
7517 (*success) = FALSE;
7518
7520 return SCIP_OKAY;
7521
7522 /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7524 leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7525
7526 if( (*cutoff) )
7527 {
7528 /* note that cutoff may occur if presolving has not been executed fully */
7529 SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7530
7531 if( tightened )
7532 {
7533 (*success) =TRUE;
7534 (*nfixedvars)++;
7535 }
7536
7537 return SCIP_OKAY;
7538 }
7539
7540 /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7541 * presolving has not been executed fully
7542 */
7543 if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7544 {
7545 /* note that cutoff may occur if presolving has not been executed fully */
7546 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7547
7548 if( tightened )
7549 {
7550 (*success) = TRUE;
7551 (*nfixedvars)++;
7552 }
7553
7554 return SCIP_OKAY;
7555 }
7556
7557 /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7558 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7559 rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7560
7561 if( (*cutoff) )
7562 {
7563 /* note that cutoff may occur if presolving has not been executed fully */
7564 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7565
7566 if( tightened )
7567 {
7568 (*success) =TRUE;
7569 (*nfixedvars)++;
7570 }
7571
7572 return SCIP_OKAY;
7573 }
7574
7575 return SCIP_OKAY;
7576}
7577
7578/** is it possible, to round variable down w.r.t. objective function */
7579static
7581 SCIP* scip, /**< SCIP data structure */
7582 SCIP_VAR* var, /**< problem variable */
7583 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7584 )
7585{
7587 int scalar;
7588
7589 assert(roundable != NULL);
7590
7591 *roundable = TRUE;
7592
7593 /* a fixed variable can be definition always be safely rounded */
7595 return SCIP_OKAY;
7596
7597 /* in case the variable is not active we need to check the object coefficient of the active variable */
7598 if( !SCIPvarIsActive(var) )
7599 {
7600 SCIP_VAR* actvar;
7601 int constant;
7602
7603 actvar = var;
7604
7605 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7606 assert(scalar != 0);
7607
7608 objval = scalar * SCIPvarGetObj(actvar);
7609 } /*lint !e438*/
7610 else
7611 {
7612 scalar = 1;
7614 }
7615
7616 /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7617 * (the transformed problem is always a minimization problem)
7618 *
7619 * @note that we need to check this condition w.r.t. active variable space
7620 */
7621 if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7622 *roundable = FALSE;
7623
7624 return SCIP_OKAY;
7625}
7626
7627/** is it possible, to round variable up w.r.t. objective function */
7628static
7630 SCIP* scip, /**< SCIP data structure */
7631 SCIP_VAR* var, /**< problem variable */
7632 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7633 )
7634{
7636 int scalar;
7637
7638 assert(roundable != NULL);
7639
7640 *roundable = TRUE;
7641
7642 /* a fixed variable can be definition always be safely rounded */
7644 return SCIP_OKAY;
7645
7646 /* in case the variable is not active we need to check the object coefficient of the active variable */
7647 if( !SCIPvarIsActive(var) )
7648 {
7649 SCIP_VAR* actvar;
7650 int constant;
7651
7652 actvar = var;
7653
7654 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7655 assert(scalar != 0);
7656
7657 objval = scalar * SCIPvarGetObj(actvar);
7658 } /*lint !e438*/
7659 else
7660 {
7661 scalar = 1;
7663 }
7664
7665 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7666 * (the transformed problem is always a minimization problem)
7667 *
7668 * @note that we need to check this condition w.r.t. active variable space
7669 */
7670 if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7671 *roundable = FALSE;
7672
7673 return SCIP_OKAY;
7674}
7675
7676/** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7677 * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7678 * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7679 * the only one locking this variable in the corresponding direction.
7680 */
7681static
7683 SCIP* scip, /**< SCIP data structure */
7684 SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7685 int nconss, /**< number of cumulative constraints */
7686 SCIP_Bool local, /**< use local bounds effective horizon? */
7687 int* alternativelbs, /**< alternative lower bounds */
7688 int* alternativeubs, /**< alternative lower bounds */
7689 int* downlocks, /**< number of constraints with down lock participating by the computation */
7690 int* uplocks /**< number of constraints with up lock participating by the computation */
7691 )
7692{
7693 int nvars;
7694 int c;
7695 int v;
7696
7697 for( c = 0; c < nconss; ++c )
7698 {
7699 SCIP_CONSDATA* consdata;
7700 SCIP_CONS* cons;
7701 SCIP_VAR* var;
7702 int hmin;
7703 int hmax;
7704
7705 cons = conss[c];
7706 assert(cons != NULL);
7707
7708 /* ignore constraints which are already deletet and those which are not check constraints */
7709 if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7710 continue;
7711
7712 consdata = SCIPconsGetData(cons);
7713 assert(consdata != NULL);
7714 assert(consdata->nvars > 1);
7715
7716 /* compute the hmin and hmax */
7717 if( local )
7718 {
7719 SCIP_PROFILE* profile;
7720 SCIP_RETCODE retcode;
7721
7722 /* create empty resource profile with infinity resource capacity */
7723 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7724
7725 /* create worst case resource profile */
7726 retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7727
7728 hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7729 hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7730
7731 /* free worst case profile */
7732 SCIPprofileFree(&profile);
7733
7734 if( retcode != SCIP_OKAY )
7735 return retcode;
7736 }
7737 else
7738 {
7739 hmin = consdata->hmin;
7740 hmax = consdata->hmax;
7741 }
7742
7743 consdata = SCIPconsGetData(cons);
7744 assert(consdata != NULL);
7745
7746 nvars = consdata->nvars;
7747
7748 for( v = 0; v < nvars; ++v )
7749 {
7750 int scalar;
7751 int constant;
7752 int idx;
7753
7754 var = consdata->vars[v];
7755 assert(var != NULL);
7756
7757 /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7759
7760 /* ignore variable locally fixed variables */
7762 continue;
7763
7764 SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7765 idx = SCIPvarGetProbindex(var);
7766 assert(idx >= 0);
7767
7768 /* first check lower bound fixing */
7769 if( consdata->downlocks[v] )
7770 {
7771 int ect;
7772 int est;
7773
7774 /* the variable has a down locked */
7775 est = scalar * boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7776 ect = est + consdata->durations[v];
7777
7778 if( ect <= hmin || hmin >= hmax )
7779 downlocks[idx]++;
7780 else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7781 {
7782 alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7783 downlocks[idx]++;
7784 }
7785 }
7786
7787 /* second check upper bound fixing */
7788 if( consdata->uplocks[v] )
7789 {
7790 int duration;
7791 int lct;
7792 int lst;
7793
7794 duration = consdata->durations[v];
7795
7796 /* the variable has a up lock locked */
7797 lst = scalar * boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7798 lct = lst + duration;
7799
7800 if( lst >= hmax || hmin >= hmax )
7801 uplocks[idx]++;
7802 else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7803 {
7804 alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7805 uplocks[idx]++;
7806 }
7807 }
7808 }
7809 }
7810
7811 return SCIP_OKAY;
7812}
7813
7814/** apply all fixings which are given by the alternative bounds */
7815static
7817 SCIP* scip, /**< SCIP data structure */
7818 SCIP_VAR** vars, /**< array of active variables */
7819 int nvars, /**< number of active variables */
7820 int* alternativelbs, /**< alternative lower bounds */
7821 int* alternativeubs, /**< alternative lower bounds */
7822 int* downlocks, /**< number of constraints with down lock participating by the computation */
7823 int* uplocks, /**< number of constraints with up lock participating by the computation */
7824 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7825 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7826 )
7827{
7828 SCIP_Real* downimpllbs;
7829 SCIP_Real* downimplubs;
7830 SCIP_Real* downproplbs;
7831 SCIP_Real* downpropubs;
7832 SCIP_Real* upimpllbs;
7833 SCIP_Real* upimplubs;
7834 SCIP_Real* upproplbs;
7835 SCIP_Real* uppropubs;
7836 int v;
7837
7838 /* get temporary memory for storing probing results */
7839 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7840 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7841 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7842 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7843 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7844 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7845 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7846 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7847
7848 for( v = 0; v < nvars; ++v )
7849 {
7850 SCIP_VAR* var;
7851 SCIP_Bool infeasible;
7852 SCIP_Bool fixed;
7853 SCIP_Bool roundable;
7854 int ub;
7855 int lb;
7856
7857 var = vars[v];
7858 assert(var != NULL);
7859
7860 /* ignore variables for which no alternative bounds have been computed */
7861 if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7862 continue;
7863
7866
7867 /* ignore fixed variables */
7868 if( ub - lb <= 0 )
7869 continue;
7870
7871 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7872 {
7873 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7874
7875 if( roundable )
7876 {
7877 if( alternativelbs[v] > ub )
7878 {
7879 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7880 assert(!infeasible);
7881 assert(fixed);
7882
7883 (*nfixedvars)++;
7884
7885 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7886 * constraints
7887 */
7889 }
7890 else
7891 {
7892 SCIP_Bool success;
7893
7894 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7895 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7896 * infeasible we can apply the dual reduction; otherwise we do nothing
7897 */
7898 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7899 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7900 nfixedvars, &success, cutoff) );
7901
7902 if( success )
7903 {
7905 }
7906 }
7907 }
7908 }
7909
7912
7913 /* ignore fixed variables */
7914 if( ub - lb <= 0 )
7915 continue;
7916
7917 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7918 {
7919 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7920
7921 if( roundable )
7922 {
7923 if( alternativeubs[v] < lb )
7924 {
7925 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7926 assert(!infeasible);
7927 assert(fixed);
7928
7929 (*nfixedvars)++;
7930
7931 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7932 * constraints
7933 */
7935 }
7936 else
7937 {
7938 SCIP_Bool success;
7939
7940 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7941 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7942 * infeasible we can apply the dual reduction; otherwise we do nothing
7943 */
7944 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7945 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7946 nfixedvars, &success, cutoff) );
7947
7948 if( success )
7949 {
7951 }
7952 }
7953 }
7954 }
7955 }
7956
7957 /* free temporary memory */
7958 SCIPfreeBufferArray(scip, &uppropubs);
7959 SCIPfreeBufferArray(scip, &upproplbs);
7960 SCIPfreeBufferArray(scip, &upimplubs);
7961 SCIPfreeBufferArray(scip, &upimpllbs);
7962 SCIPfreeBufferArray(scip, &downpropubs);
7963 SCIPfreeBufferArray(scip, &downproplbs);
7964 SCIPfreeBufferArray(scip, &downimplubs);
7965 SCIPfreeBufferArray(scip, &downimpllbs);
7966
7967 return SCIP_OKAY;
7968}
7969
7970/** propagate all constraints together */
7971static
7973 SCIP* scip, /**< SCIP data structure */
7974 SCIP_CONS** conss, /**< all cumulative constraint */
7975 int nconss, /**< number of cumulative constraints */
7976 SCIP_Bool local, /**< use local bounds effective horizon? */
7977 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7978 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7979 SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7980 )
7981{ /*lint --e{715}*/
7982 SCIP_VAR** vars;
7983 int* downlocks;
7984 int* uplocks;
7985 int* alternativelbs;
7986 int* alternativeubs;
7987 int oldnfixedvars;
7988 int nvars;
7989 int v;
7990
7992 return SCIP_OKAY;
7993
7995 oldnfixedvars = *nfixedvars;
7996
7998 SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8000 SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8001 SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8002
8003 /* initialize arrays */
8004 for( v = 0; v < nvars; ++v )
8005 {
8006 downlocks[v] = 0;
8007 uplocks[v] = 0;
8008 alternativelbs[v] = INT_MAX;
8009 alternativeubs[v] = INT_MIN;
8010 }
8011
8012 /* compute alternative bounds */
8013 SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8014
8015 /* apply fixing which result of the alternative bounds directly */
8016 SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8017 nfixedvars, cutoff) );
8018
8019 if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8020 {
8021 SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8022 }
8023
8024 /* free all buffers */
8025 SCIPfreeBufferArray(scip, &alternativeubs);
8026 SCIPfreeBufferArray(scip, &alternativelbs);
8027 SCIPfreeBufferArray(scip, &uplocks);
8028 SCIPfreeBufferArray(scip, &downlocks);
8030
8031 return SCIP_OKAY;
8032}
8033
8034/**@} */
8035
8036/**@name Linear relaxations
8037 *
8038 * @{
8039 */
8040
8041/** creates covering cuts for jobs violating resource constraints */
8042static
8044 SCIP* scip, /**< SCIP data structure */
8045 SCIP_CONS* cons, /**< constraint to be checked */
8046 int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8047 int time /**< at this point in time covering constraints are valid */
8048 )
8049{
8050 SCIP_CONSDATA* consdata;
8051 SCIP_ROW* row;
8052 int* flexibleids;
8053 int* demands;
8054
8055 char rowname[SCIP_MAXSTRLEN];
8056
8057 int remainingcap;
8058 int smallcoversize; /* size of a small cover */
8059 int bigcoversize; /* size of a big cover */
8060 int nvars;
8061
8062 int nflexible;
8063 int sumdemand; /* demand of all jobs up to a certain index */
8064 int j;
8065
8066 assert(cons != NULL);
8067
8068 /* get constraint data structure */
8069 consdata = SCIPconsGetData(cons);
8070 assert(consdata != NULL );
8071
8072 nvars = consdata->nvars;
8073
8074 /* sort jobs according to demands */
8076 SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8077
8078 nflexible = 0;
8079 remainingcap = consdata->capacity;
8080
8081 /* get all jobs intersecting point 'time' with their bounds */
8082 for( j = 0; j < nvars; ++j )
8083 {
8084 int ub;
8085
8086 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8087
8088 /* only add jobs to array if they intersect with point 'time' */
8089 if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8090 {
8091 /* if job is fixed, capacity has to be decreased */
8092 if( startvalues[j] == ub )
8093 {
8094 remainingcap -= consdata->demands[j];
8095 }
8096 else
8097 {
8098 demands[nflexible] = consdata->demands[j];
8099 flexibleids[nflexible] = j;
8100 ++nflexible;
8101 }
8102 }
8103 }
8104 assert(remainingcap >= 0);
8105
8106 /* sort demands and job ids */
8107 SCIPsortIntInt(demands, flexibleids, nflexible);
8108
8109 /*
8110 * version 1:
8111 * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8112 * erzeuge cover constraint
8113 *
8114 */
8115
8116 /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8117 sumdemand = 0;
8118 j = 0;
8119
8120 while( j < nflexible && sumdemand <= remainingcap )
8121 {
8122 sumdemand += demands[j];
8123 j++;
8124 }
8125
8126 /* j jobs form a conflict, set coversize to 'j - 1' */
8127 bigcoversize = j-1;
8128 assert(sumdemand > remainingcap);
8129 assert(bigcoversize < nflexible);
8130
8131 /* - create a row for all jobs and their binary variables.
8132 * - at most coversize many binary variables of jobs can be set to one
8133 */
8134
8135 /* construct row name */
8136 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8137 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8138 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8140
8141 for( j = 0; j < nflexible; ++j )
8142 {
8143 SCIP_VAR** binvars;
8144 SCIP_Real* vals;
8145 int nbinvars;
8146 int idx;
8147 int start;
8148 int end;
8149 int lb;
8150 int ub;
8151 int b;
8152
8153 idx = flexibleids[j];
8154
8155 /* get and add binvars into var array */
8156 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8157 assert(nbinvars != 0);
8158
8159 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8160 assert(vals != NULL);
8161
8162 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8163 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8164
8165 /* compute start and finishing time */
8166 start = time - consdata->durations[idx] + 1;
8167 end = MIN(time, ub);
8168
8169 /* add all neccessary binary variables */
8170 for( b = 0; b < nbinvars; ++b )
8171 {
8172 if( vals[b] < start || vals[b] < lb )
8173 continue;
8174
8175 if( vals[b] > end )
8176 break;
8177
8178 assert(binvars[b] != NULL);
8179 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8180 }
8181 }
8182
8183 /* insert and release row */
8185
8186 if( consdata->bcoverrowssize == 0 )
8187 {
8188 consdata->bcoverrowssize = 10;
8189 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8190 }
8191 if( consdata->nbcoverrows == consdata->bcoverrowssize )
8192 {
8193 consdata->bcoverrowssize *= 2;
8194 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8195 }
8196
8197 consdata->bcoverrows[consdata->nbcoverrows] = row;
8198 consdata->nbcoverrows++;
8199
8200 /*
8201 * version 2:
8202 * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8203 * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8204 */
8205 /* find maximum number of jobs that can run in parallel (= coversize -1) */
8206 sumdemand = 0;
8207 j = nflexible -1;
8208 while( sumdemand <= remainingcap )
8209 {
8210 assert(j >= 0);
8211 sumdemand += demands[j];
8212 j--;
8213 }
8214
8215 smallcoversize = nflexible - (j + 1) - 1;
8216 while( j > 0 && demands[j] == demands[nflexible-1] )
8217 --j;
8218
8219 assert(smallcoversize < nflexible);
8220
8221 if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8222 {
8223 /* construct row name */
8224 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8225 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8226 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8228
8229 /* filter binary variables for each unfixed job */
8230 for( j = j + 1; j < nflexible; ++j )
8231 {
8232 SCIP_VAR** binvars;
8233 SCIP_Real* vals;
8234 int nbinvars;
8235 int idx;
8236 int start;
8237 int end;
8238 int lb;
8239 int ub;
8240 int b;
8241
8242 idx = flexibleids[j];
8243
8244 /* get and add binvars into var array */
8245 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8246 assert(nbinvars != 0);
8247
8248 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8249 assert(vals != NULL);
8250
8251 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8252 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8253
8254 /* compute start and finishing time */
8255 start = time - consdata->durations[idx] + 1;
8256 end = MIN(time, ub);
8257
8258 /* add all neccessary binary variables */
8259 for( b = 0; b < nbinvars; ++b )
8260 {
8261 if( vals[b] < start || vals[b] < lb )
8262 continue;
8263
8264 if( vals[b] > end )
8265 break;
8266
8267 assert(binvars[b] != NULL);
8268 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8269 }
8270 }
8271
8272 /* insert and release row */
8274 if( consdata->scoverrowssize == 0 )
8275 {
8276 consdata->scoverrowssize = 10;
8277 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8278 }
8279 if( consdata->nscoverrows == consdata->scoverrowssize )
8280 {
8281 consdata->scoverrowssize *= 2;
8282 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8283 }
8284
8285 consdata->scoverrows[consdata->nscoverrows] = row;
8286 consdata->nscoverrows++;
8287 }
8288
8289 /* free buffer arrays */
8290 SCIPfreeBufferArray(scip, &flexibleids);
8291 SCIPfreeBufferArray(scip, &demands);
8292
8293 return SCIP_OKAY;
8294}
8295
8296/** method to construct cover cuts for all points in time */
8297static
8299 SCIP* scip, /**< SCIP data structure */
8300 SCIP_CONS* cons /**< constraint to be separated */
8301 )
8302{
8303 SCIP_CONSDATA* consdata;
8304
8305 int* startvalues; /* stores when each job is starting */
8306 int* endvalues; /* stores when each job ends */
8307 int* startvaluessorted; /* stores when each job is starting */
8308 int* endvaluessorted; /* stores when each job ends */
8309 int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8310 int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8311
8312 int nvars; /* number of jobs for this constraint */
8313 int freecapacity; /* remaining capacity */
8314 int curtime; /* point in time which we are just checking */
8315 int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8316
8317 int hmin;
8318 int hmax;
8319
8320 int j;
8321 int t;
8322
8323 assert(scip != NULL);
8324 assert(cons != NULL);
8325
8326 consdata = SCIPconsGetData(cons);
8327 assert(consdata != NULL);
8328
8329 /* if no activities are associated with this resource then this constraint is redundant */
8330 if( consdata->vars == NULL )
8331 return SCIP_OKAY;
8332
8333 nvars = consdata->nvars;
8334 hmin = consdata->hmin;
8335 hmax = consdata->hmax;
8336
8337 SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8338 SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8339 SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8340 SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8341 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8342 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8343
8344 /* assign start and endpoints to arrays */
8345 for ( j = 0; j < nvars; ++j )
8346 {
8347 startvalues[j] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8348 startvaluessorted[j] = startvalues[j];
8349
8350 endvalues[j] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8351 endvaluessorted[j] = endvalues[j];
8352
8353 startindices[j] = j;
8354 endindices[j] = j;
8355 }
8356
8357 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8358 * (and sort the indices in the same way) */
8359 SCIPsortIntInt(startvaluessorted, startindices, nvars);
8360 SCIPsortIntInt(endvaluessorted, endindices, nvars);
8361
8362 endidx = 0;
8363 freecapacity = consdata->capacity;
8364
8365 /* check each startpoint of a job whether the capacity is kept or not */
8366 for( j = 0; j < nvars; ++j )
8367 {
8368 curtime = startvaluessorted[j];
8369 if( curtime >= hmax )
8370 break;
8371
8372 /* subtract all capacity needed up to this point */
8373 freecapacity -= consdata->demands[startindices[j]];
8374
8375 while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8376 {
8377 ++j;
8378 freecapacity -= consdata->demands[startindices[j]];
8379 }
8380
8381 /* free all capacity usages of jobs the are no longer running */
8382 while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8383 {
8384 freecapacity += consdata->demands[endindices[endidx]];
8385 ++endidx;
8386 }
8387
8388 assert(freecapacity <= consdata->capacity);
8389 assert(endidx <= nvars);
8390
8391 /* --> endindex - points to the next job which will finish
8392 * j - points to the last job that has been released
8393 */
8394
8395 /* check freecapacity to be smaller than zero
8396 * then we will add cover constraints to the MIP
8397 */
8398 if( freecapacity < 0 && curtime >= hmin )
8399 {
8400 int nextprofilechange;
8401
8402 /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8403 if( j < nvars-1 )
8404 nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8405 else
8406 nextprofilechange = endvaluessorted[endidx];
8407
8408 nextprofilechange = MIN(nextprofilechange, hmax);
8409
8410 for( t = curtime; t < nextprofilechange; ++t )
8411 {
8412 SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8413
8414 /* create covering constraint */
8415 SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8416 }
8417 } /* end if freecapacity > 0 */
8418 } /*lint --e{850}*/
8419
8420 consdata->covercuts = TRUE;
8421
8422 /* free all buffer arrays */
8423 SCIPfreeBufferArray(scip, &endindices);
8424 SCIPfreeBufferArray(scip, &startindices);
8425 SCIPfreeBufferArray(scip, &endvaluessorted);
8426 SCIPfreeBufferArray(scip, &startvaluessorted);
8427 SCIPfreeBufferArray(scip, &endvalues);
8428 SCIPfreeBufferArray(scip, &startvalues);
8429
8430 return SCIP_OKAY;
8431}
8432
8433/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8434 * constraint
8435 */
8436static
8438 SCIP* scip, /**< SCIP data structure */
8439 SCIP_CONS* cons, /**< constraint to be checked */
8440 int* startindices, /**< permutation with rspect to the start times */
8441 int curtime, /**< current point in time */
8442 int nstarted, /**< number of jobs that start before the curtime or at curtime */
8443 int nfinished, /**< number of jobs that finished before curtime or at curtime */
8444 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8445 )
8446{
8447 SCIP_CONSDATA* consdata;
8448 SCIP_VAR** binvars;
8449 int* coefs;
8450 int nbinvars;
8451 char name[SCIP_MAXSTRLEN];
8452 int capacity;
8453 int b;
8454
8455 assert(nstarted > nfinished);
8456
8457 consdata = SCIPconsGetData(cons);
8458 assert(consdata != NULL);
8459 assert(consdata->nvars > 0);
8460
8461 capacity = consdata->capacity;
8462 assert(capacity > 0);
8463
8464 nbinvars = 0;
8465 SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8466
8467 /* construct row name */
8468 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8469
8470 if( cutsasconss )
8471 {
8472 SCIP_CONS* lincons;
8473
8474 /* create knapsack constraint for the given time point */
8475 SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8477
8478 for( b = 0; b < nbinvars; ++b )
8479 {
8480 SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8481 }
8482
8483 /* add and release the new constraint */
8484 SCIP_CALL( SCIPaddCons(scip, lincons) );
8485 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8486 }
8487 else
8488 {
8489 SCIP_ROW* row;
8490
8491 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8493
8494 for( b = 0; b < nbinvars; ++b )
8495 {
8496 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8497 }
8498
8501
8502 if( consdata->demandrowssize == 0 )
8503 {
8504 consdata->demandrowssize = 10;
8505 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8506 }
8507 if( consdata->ndemandrows == consdata->demandrowssize )
8508 {
8509 consdata->demandrowssize *= 2;
8510 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8511 }
8512
8513 consdata->demandrows[consdata->ndemandrows] = row;
8514 consdata->ndemandrows++;
8515 }
8516
8517 SCIPfreeBufferArrayNull(scip, &binvars);
8519
8520 return SCIP_OKAY;
8521}
8522
8523/** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8524 * row
8525 */
8526static
8528 SCIP* scip, /**< SCIP data structure */
8529 SCIP_CONS* cons, /**< constraint to be checked */
8530 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8531 )
8532{
8533 SCIP_CONSDATA* consdata;
8534
8535 int* starttimes; /* stores when each job is starting */
8536 int* endtimes; /* stores when each job ends */
8537 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8538 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8539
8540 int nvars; /* number of activities for this constraint */
8541 int freecapacity; /* remaining capacity */
8542 int curtime; /* point in time which we are just checking */
8543 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8544
8545 int hmin;
8546 int hmax;
8547
8548 int j;
8549
8550 assert(scip != NULL);
8551 assert(cons != NULL);
8552
8553 consdata = SCIPconsGetData(cons);
8554 assert(consdata != NULL);
8555
8556 nvars = consdata->nvars;
8557
8558 /* if no activities are associated with this cumulative then this constraint is redundant */
8559 if( nvars == 0 )
8560 return SCIP_OKAY;
8561
8562 assert(consdata->vars != NULL);
8563
8564 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8565 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8566 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8567 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8568
8569 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8570 SCIPconsGetName(cons), nvars);
8571
8572 /* create event point arrays */
8573 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8574 starttimes, endtimes, startindices, endindices, FALSE);
8575
8576 endindex = 0;
8577 freecapacity = consdata->capacity;
8578 hmin = consdata->hmin;
8579 hmax = consdata->hmax;
8580
8581 /* check each startpoint of a job whether the capacity is kept or not */
8582 for( j = 0; j < nvars; ++j )
8583 {
8584 curtime = starttimes[j];
8585 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8586
8587 if( curtime >= hmax )
8588 break;
8589
8590 /* remove the capacity requirments for all job which start at the curtime */
8591 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8592
8593 /* add the capacity requirments for all job which end at the curtime */
8594 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8595
8596 assert(freecapacity <= consdata->capacity);
8597 assert(endindex <= nvars);
8598
8599 /* endindex - points to the next job which will finish */
8600 /* j - points to the last job that has been released */
8601
8602 /* if free capacity is smaller than zero, then add rows to the LP */
8603 if( freecapacity < 0 && curtime >= hmin )
8604 {
8605 int nextstarttime;
8606 int t;
8607
8608 /* step forward until next job is released and see whether capacity constraint is met or not */
8609 if( j < nvars-1 )
8610 nextstarttime = starttimes[j+1];
8611 else
8612 nextstarttime = endtimes[nvars-1];
8613
8614 nextstarttime = MIN(nextstarttime, hmax);
8615
8616 /* create capacity restriction row for current event point */
8617 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8618
8619 /* create for all points in time between the current event point and next start event point a row if the free
8620 * capacity is still smaller than zero */
8621 for( t = curtime+1 ; t < nextstarttime; ++t )
8622 {
8623 /* add the capacity requirments for all job which end at the curtime */
8624 addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8625
8626 if( freecapacity < 0 )
8627 {
8628 /* add constraint */
8629 SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8630
8631 /* create capacity restriction row */
8632 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8633 }
8634 else
8635 break;
8636 }
8637 }
8638 } /*lint --e{850}*/
8639
8640 /* free all buffer arrays */
8641 SCIPfreeBufferArray(scip, &endindices);
8642 SCIPfreeBufferArray(scip, &startindices);
8643 SCIPfreeBufferArray(scip, &endtimes);
8644 SCIPfreeBufferArray(scip, &starttimes);
8645
8646 return SCIP_OKAY;
8647}
8648
8649/** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8650 * capacity is larger than the capacity of the cumulative constraint
8651 * - for each necessary point in time:
8652 *
8653 * sum_j sum_t demand_j * x_{j,t} <= capacity
8654 *
8655 * where x(j,t) is the binary variables of job j at time t
8656 */
8657static
8659 SCIP* scip, /**< SCIP data structure */
8660 SCIP_CONS* cons, /**< cumulative constraint */
8661 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8662 )
8663{
8664 SCIP_CONSDATA* consdata;
8665
8666 consdata = SCIPconsGetData(cons);
8667 assert(consdata != NULL);
8668 assert(consdata->demandrows == NULL);
8669 assert(consdata->ndemandrows == 0);
8670
8671 /* collect the linking constraints */
8672 if( consdata->linkingconss == NULL )
8673 {
8675 }
8676
8677 SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8678
8679 /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8680 if( cutsasconss )
8681 {
8682 if( SCIPconsIsInitial(cons) )
8683 {
8685 }
8686 if( SCIPconsIsSeparated(cons) )
8687 {
8689 }
8690 if( SCIPconsIsEnforced(cons) )
8691 {
8693 }
8694 }
8695
8696 return SCIP_OKAY;
8697}
8698
8699/** adds linear relaxation of cumulative constraint to the LP */
8700static
8702 SCIP* scip, /**< SCIP data structure */
8703 SCIP_CONS* cons, /**< cumulative constraint */
8704 SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8705 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8706 )
8707{
8708 SCIP_CONSDATA* consdata;
8709 int r;
8710
8711 consdata = SCIPconsGetData(cons);
8712 assert(consdata != NULL);
8713
8714 if( consdata->demandrows == NULL )
8715 {
8716 assert(consdata->ndemandrows == 0);
8717
8718 SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8719
8720 return SCIP_OKAY;
8721 }
8722
8723 for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8724 {
8725 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8726 {
8727 assert(consdata->demandrows[r] != NULL);
8728 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8729 }
8730 }
8731
8732 return SCIP_OKAY;
8733}
8734
8735/** checks constraint for violation, and adds it as a cut if possible */
8736static
8738 SCIP* scip, /**< SCIP data structure */
8739 SCIP_CONS* cons, /**< cumulative constraint to be separated */
8740 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8741 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8742 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8743 )
8744{ /*lint --e{715}*/
8745 SCIP_CONSDATA* consdata;
8746 int ncuts;
8747 int r;
8748
8749 assert(scip != NULL);
8750 assert(cons != NULL);
8751 assert(separated != NULL);
8752 assert(cutoff != NULL);
8753
8754 *separated = FALSE;
8755 *cutoff = FALSE;
8756
8757 consdata = SCIPconsGetData(cons);
8758 assert(consdata != NULL);
8759
8760 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8761
8762 if( consdata->demandrows == NULL )
8763 {
8764 assert(consdata->ndemandrows == 0);
8765
8767
8768 return SCIP_OKAY;
8769 }
8770
8771 ncuts = 0;
8772
8773 /* check each row that is not contained in LP */
8774 for( r = 0; r < consdata->ndemandrows; ++r )
8775 {
8776 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8777 {
8778 SCIP_Real feasibility;
8779
8780 if( sol != NULL )
8781 feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8782 else
8783 feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8784
8785 if( SCIPisFeasNegative(scip, feasibility) )
8786 {
8787 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8788 if ( *cutoff )
8789 {
8791 return SCIP_OKAY;
8792 }
8793 *separated = TRUE;
8794 ncuts++;
8795 }
8796 }
8797 }
8798
8799 if( ncuts > 0 )
8800 {
8801 SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8802
8803 /* if successful, reset age of constraint */
8805 (*separated) = TRUE;
8806 }
8807
8808 return SCIP_OKAY;
8809}
8810
8811/** checks constraint for violation, and adds it as a cut if possible */
8812static
8814 SCIP* scip, /**< SCIP data structure */
8815 SCIP_CONS* cons, /**< logic or constraint to be separated */
8816 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8817 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8818 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8819 )
8820{
8821 SCIP_CONSDATA* consdata;
8822 SCIP_ROW* row;
8823 SCIP_Real minfeasibility;
8824 int r;
8825
8826 assert(scip != NULL);
8827 assert(cons != NULL);
8828 assert(separated != NULL);
8829 assert(cutoff != NULL);
8830
8831 *separated = FALSE;
8832 *cutoff = FALSE;
8833
8834 consdata = SCIPconsGetData(cons);
8835 assert(consdata != NULL);
8836
8837 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8838
8839 /* collect the linking constraints */
8840 if( consdata->linkingconss == NULL )
8841 {
8843 }
8844
8845 if( !consdata->covercuts )
8846 {
8847 SCIP_CALL( createCoverCuts(scip, cons) );
8848 }
8849
8850 row = NULL;
8851 minfeasibility = SCIPinfinity(scip);
8852
8853 /* check each row of small covers that is not contained in LP */
8854 for( r = 0; r < consdata->nscoverrows; ++r )
8855 {
8856 if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8857 {
8858 SCIP_Real feasibility;
8859
8860 assert(consdata->scoverrows[r] != NULL);
8861 if( sol != NULL )
8862 feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8863 else
8864 feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8865
8866 if( minfeasibility > feasibility )
8867 {
8868 minfeasibility = feasibility;
8869 row = consdata->scoverrows[r];
8870 }
8871 }
8872 }
8873
8874 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8875
8876 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8877 {
8878 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8879 SCIPconsGetName(cons), minfeasibility);
8880
8883 if ( *cutoff )
8884 return SCIP_OKAY;
8885 (*separated) = TRUE;
8886 }
8887
8888 minfeasibility = SCIPinfinity(scip);
8889 row = NULL;
8890
8891 /* check each row of small covers that is not contained in LP */
8892 for( r = 0; r < consdata->nbcoverrows; ++r )
8893 {
8894 if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8895 {
8896 SCIP_Real feasibility;
8897
8898 assert(consdata->bcoverrows[r] != NULL);
8899 if( sol != NULL )
8900 feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8901 else
8902 feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8903
8904 if( minfeasibility > feasibility )
8905 {
8906 minfeasibility = feasibility;
8907 row = consdata->bcoverrows[r];
8908 }
8909 }
8910 }
8911
8912 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8913
8914 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8915 {
8916 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8917 SCIPconsGetName(cons), minfeasibility);
8918
8919 assert(row != NULL);
8922 if ( *cutoff )
8923 return SCIP_OKAY;
8924 (*separated) = TRUE;
8925 }
8926
8927 return SCIP_OKAY;
8928}
8929
8930/** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8931static
8933 SCIP* scip, /**< SCIP data structure */
8934 SCIP_CONS* cons, /**< constraint to be checked */
8935 int* startindices, /**< permutation with rspect to the start times */
8936 int curtime, /**< current point in time */
8937 int nstarted, /**< number of jobs that start before the curtime or at curtime */
8938 int nfinished, /**< number of jobs that finished before curtime or at curtime */
8939 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
8940 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
8941 )
8942{
8943 SCIP_CONSDATA* consdata;
8944 char name[SCIP_MAXSTRLEN];
8945 int lhs; /* left hand side of constraint */
8946
8947 SCIP_VAR** activevars;
8948 SCIP_ROW* row;
8949
8950 int v;
8951
8952 assert(nstarted > nfinished);
8953
8954 consdata = SCIPconsGetData(cons);
8955 assert(consdata != NULL);
8956 assert(consdata->nvars > 0);
8957
8958 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8959
8960 SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8961
8962 if( lower )
8963 {
8964 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8965
8966 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
8967 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8968 }
8969 else
8970 {
8971 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8972 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8973 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8974 }
8975
8977
8978 for( v = 0; v < nstarted - nfinished; ++v )
8979 {
8980 SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
8981 }
8982
8985
8986 SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
8987
8988 SCIP_CALL( SCIPreleaseRow(scip, &row) );
8989
8990 /* free buffers */
8991 SCIPfreeBufferArrayNull(scip, &activevars);
8992
8993 return SCIP_OKAY;
8994}
8995
8996/** checks constraint for violation, and adds it as a cut if possible */
8997static
8999 SCIP* scip, /**< SCIP data structure */
9000 SCIP_CONS* cons, /**< cumulative constraint to be separated */
9001 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9002 SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9003 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9004 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9005 )
9006{
9007 SCIP_CONSDATA* consdata;
9008
9009 int* starttimes; /* stores when each job is starting */
9010 int* endtimes; /* stores when each job ends */
9011 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9012 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9013
9014 int nvars; /* number of activities for this constraint */
9015 int freecapacity; /* remaining capacity */
9016 int curtime; /* point in time which we are just checking */
9017 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9018
9019 int hmin;
9020 int hmax;
9021 int j;
9022
9023 assert(scip != NULL);
9024 assert(cons != NULL);
9025
9026 consdata = SCIPconsGetData(cons);
9027 assert(consdata != NULL);
9028
9029 nvars = consdata->nvars;
9030
9031 /* if no activities are associated with this cumulative then this constraint is redundant */
9032 if( nvars <= 1 )
9033 return SCIP_OKAY;
9034
9035 assert(consdata->vars != NULL);
9036
9037 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9038 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9039 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9040 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9041
9042 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9043 SCIPconsGetName(cons), nvars);
9044
9045 /* create event point arrays */
9046 createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9047
9048 /* now nvars might be smaller than before! */
9049
9050 endindex = 0;
9051 freecapacity = consdata->capacity;
9052 hmin = consdata->hmin;
9053 hmax = consdata->hmax;
9054
9055 /* check each startpoint of a job whether the capacity is kept or not */
9056 for( j = 0; j < nvars && !(*cutoff); ++j )
9057 {
9058 curtime = starttimes[j];
9059
9060 if( curtime >= hmax )
9061 break;
9062
9063 /* remove the capacity requirements for all job which start at the curtime */
9064 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9065
9066 /* add the capacity requirments for all job which end at the curtime */
9067 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9068
9069 assert(freecapacity <= consdata->capacity);
9070 assert(endindex <= nvars);
9071
9072 /* endindex - points to the next job which will finish */
9073 /* j - points to the last job that has been released */
9074
9075 /* if free capacity is smaller than zero, then add rows to the LP */
9076 if( freecapacity < 0 && curtime >= hmin)
9077 {
9078 /* create capacity restriction row for current event point */
9079 SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9080 *separated = TRUE;
9081 }
9082 } /*lint --e{850}*/
9083
9084 /* free all buffer arrays */
9085 SCIPfreeBufferArray(scip, &endindices);
9086 SCIPfreeBufferArray(scip, &startindices);
9087 SCIPfreeBufferArray(scip, &endtimes);
9088 SCIPfreeBufferArray(scip, &starttimes);
9089
9090 return SCIP_OKAY;
9091}
9092
9093/**@} */
9094
9095
9096/**@name Presolving
9097 *
9098 * @{
9099 */
9100
9101#ifndef NDEBUG
9102/** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9103 * correct
9104 */
9105static
9107 SCIP* scip, /**< SCIP data structure */
9108 SCIP_CONS* cons /**< constraint to be checked */
9109 )
9110{
9111 SCIP_CONSDATA* consdata;
9112 int capacity;
9113 int nvars;
9114 int j;
9115
9116 assert(scip != NULL);
9117 assert(cons != NULL);
9118
9119 consdata = SCIPconsGetData(cons);
9120 assert(consdata != NULL);
9121
9122 nvars = consdata->nvars;
9123
9124 /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9125 if( nvars <= 1 )
9126 return TRUE;
9127
9128 assert(consdata->vars != NULL);
9129 capacity = consdata->capacity;
9130
9131 /* check each activity: if demand is larger than capacity the problem is infeasible */
9132 for ( j = 0; j < nvars; ++j )
9133 {
9134 if( consdata->demands[j] > capacity )
9135 return FALSE;
9136 }
9137
9138 return TRUE;
9139}
9140#endif
9141
9142/** delete constraint if it consists of at most one job
9143 *
9144 * @todo this method needs to be adjusted w.r.t. effective horizon
9145 */
9146static
9148 SCIP* scip, /**< SCIP data structure */
9149 SCIP_CONS* cons, /**< constraint to propagate */
9150 int* ndelconss, /**< pointer to store the number of deleted constraints */
9151 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9152 )
9153{
9154 SCIP_CONSDATA* consdata;
9155
9156 assert(scip != NULL);
9157 assert(cons != NULL);
9158
9159 consdata = SCIPconsGetData(cons);
9160 assert(consdata != NULL);
9161
9162 if( consdata->nvars == 0 )
9163 {
9164 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9165
9166 SCIP_CALL( SCIPdelCons(scip, cons) );
9167 (*ndelconss)++;
9168 }
9169 else if( consdata->nvars == 1 )
9170 {
9171 if( consdata->demands[0] > consdata->capacity )
9172 (*cutoff) = TRUE;
9173 else
9174 {
9175 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9176
9177 SCIP_CALL( SCIPdelCons(scip, cons) );
9178 (*ndelconss)++;
9179 }
9180 }
9181
9182 return SCIP_OKAY;
9183}
9184
9185/** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9186 * this is done in the SCIP_DECL_CONSINITPRE() callback
9187 */
9188static
9190 SCIP* scip, /**< SCIP data structure */
9191 SCIP_CONS* cons /**< constraint to propagate */
9192 )
9193{
9194 SCIP_CONSDATA* consdata;
9195 SCIP_VAR* var;
9196 int demand;
9197 int duration;
9198 int hmin;
9199 int hmax;
9200 int est;
9201 int lct;
9202 int j;
9203
9204 assert(scip != NULL);
9205 assert(cons != NULL);
9206
9207 consdata = SCIPconsGetData(cons);
9208 assert(consdata != NULL);
9209
9210 hmin = consdata->hmin;
9211 hmax = consdata->hmax;
9212
9213 SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9214 SCIPconsGetName(cons), hmin, hmax);
9215
9216 for( j = consdata->nvars-1; j >= 0; --j )
9217 {
9218 var = consdata->vars[j];
9219 demand = consdata->demands[j];
9220 duration = consdata->durations[j];
9221
9222 /* earliest completion time (ect) and latest start time (lst) */
9225
9226 if( demand == 0 || duration == 0 )
9227 {
9228 /* jobs with zero demand or zero duration can be removed */
9229 SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9230 SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9231
9232 /* remove variable form constraint */
9233 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9234 }
9235 else if( est >= hmax || lct <= hmin )
9236 {
9237 SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9238 SCIPvarGetName(var), est, lct - duration, duration);
9239
9240 /* delete variable at the given position */
9241 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9242
9243 /* for the statistic we count the number of jobs which are irrelevant */
9245 }
9246 }
9247
9248 return SCIP_OKAY;
9249}
9250
9251/** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9252static
9254 SCIP* scip, /**< SCIP data structure */
9255 SCIP_CONSDATA* consdata, /**< constraint data */
9256 int pos, /**< position of job in the consdata */
9257 int* nchgbds, /**< pointer to store the number of changed bounds */
9258 int* naddconss, /**< pointer to store the number of added constraints */
9259 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9260 )
9261{
9262 SCIP_VAR* var;
9263 SCIP_Bool tightened;
9264 int duration;
9265 int ect;
9266 int lst;
9267
9268 assert(scip != NULL);
9269
9270 /* zero energy jobs should be removed already */
9271 assert(consdata->durations[pos] > 0);
9272 assert(consdata->demands[pos] > 0);
9273
9274 var = consdata->vars[pos];
9275 assert(var != NULL);
9276 duration = consdata->durations[pos];
9277
9278 /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9279 SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9280 SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9281
9282 /* earliest completion time (ect) and latest start time (lst) */
9285
9286 /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9287 if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9288 return SCIP_OKAY;
9289
9290 if( ect > consdata->hmin && lst < consdata->hmax )
9291 {
9292 /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9293 *cutoff = TRUE;
9294 }
9295 else if( lst < consdata->hmax )
9296 {
9297 /* move the latest start time of this job in such a way that it finishes before or at hmin */
9298 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9299 assert(tightened);
9300 assert(!(*cutoff));
9301 (*nchgbds)++;
9302 }
9303 else if( ect > consdata->hmin )
9304 {
9305 /* move the earliest start time of this job in such a way that it starts after or at hmax */
9306 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9307 assert(tightened);
9308 assert(!(*cutoff));
9309 (*nchgbds)++;
9310 }
9311 else
9312 {
9313 /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9314 * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9315 *
9316 * (var <= hmin - duration) /\ (var >= hmax)
9317 */
9318 SCIP_CONS* cons;
9319
9320 SCIP_VAR* vartuple[2];
9321 SCIP_BOUNDTYPE boundtypetuple[2];
9322 SCIP_Real boundtuple[2];
9323
9324 char name[SCIP_MAXSTRLEN];
9325 int leftbound;
9326 int rightbound;
9327
9328 leftbound = consdata->hmin - duration;
9329 rightbound = consdata->hmax;
9330
9331 /* allocate temporary memory for arrays */
9332 vartuple[0] = var;
9333 vartuple[1] = var;
9334 boundtuple[0] = (SCIP_Real)leftbound;
9335 boundtuple[1] = (SCIP_Real)rightbound;
9336 boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9337 boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9338
9339 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9340 SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9341
9342 /* create and add bounddisjunction constraint */
9343 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9344 TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9345
9347
9348 /* add and release the new constraint */
9349 SCIP_CALL( SCIPaddCons(scip, cons) );
9350 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9351 (*naddconss)++;
9352 }
9353
9354 return SCIP_OKAY;
9355}
9356
9357/** try to removed over sizeed jobs (the demand is larger than the capacity) */
9358static
9360 SCIP* scip, /**< SCIP data structure */
9361 SCIP_CONS* cons, /**< constraint */
9362 int* nchgbds, /**< pointer to store the number of changed bounds */
9363 int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9364 int* naddconss, /**< pointer to store the number of added constraints */
9365 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9366 )
9367{
9368 SCIP_CONSDATA* consdata;
9369 int capacity;
9370 int j;
9371
9372 consdata = SCIPconsGetData(cons);
9373 assert(consdata != NULL);
9374
9375 /* if a cutoff was already detected just return */
9376 if( *cutoff )
9377 return SCIP_OKAY;
9378
9379 capacity = consdata->capacity;
9380
9381 for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9382 {
9383 if( consdata->demands[j] > capacity )
9384 {
9385 SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9386
9387 /* remove variable form constraint */
9388 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9389 (*nchgcoefs)++;
9390 }
9391 }
9392
9393 SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9394
9395 return SCIP_OKAY;
9396}
9397
9398/** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9399static
9401 SCIP* scip, /**< SCIP data structure */
9402 SCIP_VAR* var, /**< integer variable to fix */
9403 SCIP_Bool uplock, /**< has thet start time variable a up lock */
9404 int* nfixedvars /**< pointer to store the number fixed variables */
9405 )
9406{
9407 SCIP_Bool infeasible;
9408 SCIP_Bool tightened;
9409 SCIP_Bool roundable;
9410
9411 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9412 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9413 */
9415 return SCIP_OKAY;
9416
9417 /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9418 * handler is the only one locking that variable up
9419 */
9420 assert(uplock == TRUE || uplock == FALSE);
9421 assert((int)TRUE == 1); /*lint !e506*/
9422 assert((int)FALSE == 0); /*lint !e506*/
9423
9424 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9425 return SCIP_OKAY;
9426
9427 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9428
9429 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9430 * (the transformed problem is always a minimization problem)
9431 */
9432 if( !roundable )
9433 return SCIP_OKAY;
9434
9435 SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9437
9438 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9439 assert(!infeasible);
9440
9441 if( tightened )
9442 {
9443 SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9444 (*nfixedvars)++;
9445 }
9446
9447 return SCIP_OKAY;
9448}
9449
9450/** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9451static
9453 SCIP* scip, /**< SCIP data structure */
9454 SCIP_VAR* var, /**< integer variable to fix */
9455 SCIP_Bool downlock, /**< has the variable a down lock */
9456 int* nfixedvars /**< pointer to store the number fixed variables */
9457 )
9458{
9459 SCIP_Bool infeasible;
9460 SCIP_Bool tightened;
9461 SCIP_Bool roundable;
9462
9463 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9464 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9465 */
9467 return SCIP_OKAY;
9468
9469 /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9470 * handler is the only one locking that variable down
9471 */
9472 assert(downlock == TRUE || downlock == FALSE);
9473 assert((int)TRUE == 1); /*lint !e506*/
9474 assert((int)FALSE == 0); /*lint !e506*/
9475
9476 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9477 return SCIP_OKAY;
9478
9479 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9480
9481 /* is it possible, to round variable down w.r.t. objective function? */
9482 if( !roundable )
9483 return SCIP_OKAY;
9484
9485 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9486 assert(!infeasible);
9487
9488 if( tightened )
9489 {
9490 SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9491 (*nfixedvars)++;
9492 }
9493
9494 return SCIP_OKAY;
9495}
9496
9497/** normalize cumulative condition */
9498static
9500 SCIP* scip, /**< SCIP data structure */
9501 int nvars, /**< number of start time variables (activities) */
9502 int* demands, /**< array of demands */
9503 int* capacity, /**< pointer to store the changed cumulative capacity */
9504 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9505 int* nchgsides /**< pointer to count number of side changes */
9506 )
9507{ /*lint --e{715}*/
9508 SCIP_Longint gcd;
9509 int mindemand1;
9510 int mindemand2;
9511 int v;
9512
9513 if( *capacity == 1 || nvars <= 1 )
9514 return;
9515
9516 assert(demands[nvars-1] <= *capacity);
9517 assert(demands[nvars-2] <= *capacity);
9518
9519 gcd = (SCIP_Longint)demands[nvars-1];
9520 mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9521 mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9522
9523 for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9524 {
9525 assert(mindemand1 <= mindemand2);
9526 assert(demands[v] <= *capacity);
9527
9528 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9529
9530 if( mindemand1 > demands[v] )
9531 {
9532 mindemand2 = mindemand1;
9533 mindemand1 = demands[v];
9534 }
9535 else if( mindemand2 > demands[v] )
9536 mindemand2 = demands[v];
9537 }
9538
9539 if( mindemand1 + mindemand2 > *capacity )
9540 {
9541 SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9542
9543 for( v = 0; v < nvars; ++v )
9544 demands[v] = 1;
9545
9546 (*capacity) = 1;
9547
9548 (*nchgcoefs) += nvars;
9549 (*nchgsides)++;
9550 }
9551 else if( gcd >= 2 )
9552 {
9553 SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9554
9555 for( v = 0; v < nvars; ++v )
9556 demands[v] /= (int) gcd;
9557
9558 (*capacity) /= (int) gcd;
9559
9560 (*nchgcoefs) += nvars;
9561 (*nchgsides)++;
9562 }
9563}
9564
9565/** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9566 * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9567 * capacity since in that case none of the jobs can run in parallel
9568 */
9569static
9571 SCIP* scip, /**< SCIP data structure */
9572 SCIP_CONS* cons, /**< cumulative constraint */
9573 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9574 int* nchgsides /**< pointer to count number of side changes */
9575 )
9576{
9577 SCIP_CONSDATA* consdata;
9578 int capacity;
9579
9580 assert(nchgcoefs != NULL);
9581 assert(nchgsides != NULL);
9583
9584 consdata = SCIPconsGetData(cons);
9585 assert(consdata != NULL);
9586
9587 if( consdata->normalized )
9588 return;
9589
9590 capacity = consdata->capacity;
9591
9592 /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9593
9594 normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9595
9596 consdata->normalized = TRUE;
9597
9598 if( capacity > consdata->capacity )
9599 consdata->varbounds = FALSE;
9600}
9601
9602/** computes for the given cumulative condition the effective horizon */
9603static
9605 SCIP* scip, /**< SCIP data structure */
9606 int nvars, /**< number of variables (jobs) */
9607 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9608 int* durations, /**< array containing corresponding durations */
9609 int* demands, /**< array containing corresponding demands */
9610 int capacity, /**< available cumulative capacity */
9611 int* hmin, /**< pointer to store the left bound of the effective horizon */
9612 int* hmax, /**< pointer to store the right bound of the effective horizon */
9613 int* split /**< point were the cumulative condition can be split */
9614 )
9615{
9616 SCIP_PROFILE* profile;
9617
9618 /* create empty resource profile with infinity resource capacity */
9619 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9620
9621 /* create worst case resource profile */
9622 SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9623
9624 /* print resource profile in if SCIP_DEBUG is defined */
9626
9627 /* computes the first time point where the resource capacity can be violated */
9628 (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9629
9630 /* computes the first time point where the resource capacity is satisfied for sure */
9631 (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9632
9633 (*split) = (*hmax);
9634
9635 if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9636 {
9637 int* timepoints;
9638 int* loads;
9639 int ntimepoints;
9640 int t;
9641
9642 /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9643 * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9644 * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9645 * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9646 * explain the certain "old" bound changes
9647 */
9648
9649 /* search for time points */
9650 ntimepoints = SCIPprofileGetNTimepoints(profile);
9651 timepoints = SCIPprofileGetTimepoints(profile);
9652 loads = SCIPprofileGetLoads(profile);
9653
9654 /* 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 */
9655 for( t = 0; t < ntimepoints; ++t )
9656 {
9657 /* ignore all time points before the effective horizon */
9658 if( timepoints[t] <= *hmin )
9659 continue;
9660
9661 /* ignore all time points after the effective horizon */
9662 if( timepoints[t] >= *hmax )
9663 break;
9664
9665 /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9666 * can split the cumulative constraint into two cumulative constraints
9667 */
9668 if( loads[t] <= capacity )
9669 {
9670 (*split) = timepoints[t];
9671 break;
9672 }
9673 }
9674 }
9675
9676 /* free worst case profile */
9677 SCIPprofileFree(&profile);
9678
9679 return SCIP_OKAY;
9680}
9681
9682/** creates and adds a cumulative constraint */
9683static
9685 SCIP* scip, /**< SCIP data structure */
9686 const char* name, /**< name of constraint */
9687 int nvars, /**< number of variables (jobs) */
9688 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9689 int* durations, /**< array containing corresponding durations */
9690 int* demands, /**< array containing corresponding demands */
9691 int capacity, /**< available cumulative capacity */
9692 int hmin, /**< left bound of time axis to be considered (including hmin) */
9693 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9694 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9695 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9696 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9697 * Usually set to TRUE. */
9698 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9699 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9700 SCIP_Bool check, /**< should the constraint be checked for feasibility?
9701 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9702 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9703 * Usually set to TRUE. */
9704 SCIP_Bool local, /**< is constraint only valid locally?
9705 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9706 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9707 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9708 * adds coefficients to this constraint. */
9709 SCIP_Bool dynamic, /**< is constraint subject to aging?
9710 * Usually set to FALSE. Set to TRUE for own cuts which
9711 * are seperated as constraints. */
9712 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9713 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9714 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9715 * if it may be moved to a more global node?
9716 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9717 )
9718{
9719 SCIP_CONS* cons;
9720
9721 /* creates cumulative constraint and adds it to problem */
9722 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9723 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9724
9725 /* adjust the effective time horizon of the new constraint */
9726 SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9727 SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9728
9729 /* add and release new cumulative constraint */
9730 SCIP_CALL( SCIPaddCons(scip, cons) );
9731 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9732
9733 return SCIP_OKAY;
9734}
9735
9736/** computes the effective horizon and checks if the constraint can be decompsed */
9737static
9739 SCIP* scip, /**< SCIP data structure */
9740 SCIP_CONS* cons, /**< cumulative constraint */
9741 int* ndelconss, /**< pointer to store the number of deleted constraints */
9742 int* naddconss, /**< pointer to store the number of added constraints */
9743 int* nchgsides /**< pointer to store the number of changed sides */
9744 )
9745{
9746 SCIP_CONSDATA* consdata;
9747 int hmin;
9748 int hmax;
9749 int split;
9750
9751 consdata = SCIPconsGetData(cons);
9752 assert(consdata != NULL);
9753
9754 if( consdata->nvars <= 1 )
9755 return SCIP_OKAY;
9756
9757 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9758 consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9759
9760 /* check if this time point improves the effective horizon */
9761 if( consdata->hmin < hmin )
9762 {
9763 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9764
9765 consdata->hmin = hmin;
9766 (*nchgsides)++;
9767 }
9768
9769 /* check if this time point improves the effective horizon */
9770 if( consdata->hmax > hmax )
9771 {
9772 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9773 consdata->hmax = hmax;
9774 (*nchgsides)++;
9775 }
9776
9777 /* check if the constraint is redundant */
9778 if( consdata->hmax <= consdata->hmin )
9779 {
9780 SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9781 SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9782
9783 SCIP_CALL( SCIPdelCons(scip, cons) );
9784 (*ndelconss)++;
9785 }
9786 else if( consdata->hmin < split && split < consdata->hmax )
9787 {
9788 char name[SCIP_MAXSTRLEN];
9789 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9790
9791 SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9792 SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9793
9794 assert(split < consdata->hmax);
9795
9796 /* creates cumulative constraint and adds it to problem */
9797 SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9798 consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9801
9802 /* adjust the effective time horizon of the constraint */
9803 consdata->hmax = split;
9804
9805 assert(consdata->hmin < consdata->hmax);
9806
9807 /* for the statistic we count the number of time we decompose a cumulative constraint */
9809 (*naddconss)++;
9810 }
9811
9812 return SCIP_OKAY;
9813}
9814
9815
9816/** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9817 *
9818 * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9819 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9820 *
9821 * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9822 * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9823 * down-lock of the corresponding start time variable can be removed.
9824 *
9825 * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9826 * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9827 * negative, than the job can be dual fixed to its earlier start time (est).
9828 *
9829 * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9830 * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9831 * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9832 *
9833 * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9834 * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9835 * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9836 * form variable domain is dual feasible.
9837 *
9838 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9839 * the cumulative condition; The deletion has to be done later.
9840 */
9841static
9843 SCIP* scip, /**< SCIP data structure */
9844 int nvars, /**< number of start time variables (activities) */
9845 SCIP_VAR** vars, /**< array of start time variables */
9846 int* durations, /**< array of durations */
9847 int hmin, /**< left bound of time axis to be considered (including hmin) */
9848 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9849 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9850 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9851 SCIP_CONS* cons, /**< underlying constraint, or NULL */
9852 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9853 int* nfixedvars, /**< pointer to store the number of fixed variables */
9854 int* nchgsides, /**< pointer to store the number of changed sides */
9855 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9856 )
9857{
9858 SCIP_Real* downimpllbs;
9859 SCIP_Real* downimplubs;
9860 SCIP_Real* downproplbs;
9861 SCIP_Real* downpropubs;
9862 SCIP_Real* upimpllbs;
9863 SCIP_Real* upimplubs;
9864 SCIP_Real* upproplbs;
9865 SCIP_Real* uppropubs;
9866
9867 int firstminect;
9868 int secondminect;
9869 int v;
9870
9871 /* get temporary memory for storing probing results needed for step (4) and (5) */
9872 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9873 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9874 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9875 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9876 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9877 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9878 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9879 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9880
9881 assert(scip != NULL);
9882 assert(nvars > 1);
9883 assert(cons != NULL);
9884
9885 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9886
9887 firstminect = INT_MAX;
9888 secondminect = INT_MAX;
9889
9890 /* compute the two smallest earlier completion times; which are needed for step (5) */
9891 for( v = 0; v < nvars; ++v )
9892 {
9893 int ect;
9894
9895 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9896
9897 if( ect < firstminect )
9898 {
9899 secondminect = firstminect;
9900 firstminect = ect;
9901 }
9902 else if( ect < secondminect )
9903 secondminect = ect;
9904 }
9905
9906 /* loop over all jobs and check if one of the 5 reductions can be applied */
9907 for( v = 0; v < nvars; ++v )
9908 {
9909 SCIP_VAR* var;
9910 int duration;
9911
9912 int alternativelb;
9913 int minect;
9914 int est;
9915 int ect;
9916 int lst;
9917 int lct;
9918
9919 var = vars[v];
9920 assert(var != NULL);
9921
9922 duration = durations[v];
9923 assert(duration > 0);
9924
9925 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9926 * time (lct)
9927 */
9929 ect = est + duration;
9931 lct = lst + duration;
9932
9933 /* compute the earliest completion time of all remaining jobs */
9934 if( ect == firstminect )
9935 minect = secondminect;
9936 else
9937 minect = firstminect;
9938
9939 /* compute potential alternative lower bound (step (4) and (5)) */
9940 alternativelb = MAX(hmin+1, minect);
9941 alternativelb = MIN(alternativelb, hmax);
9942
9943 if( lct <= hmin )
9944 {
9945 /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9946 * cumulative condition
9947 */
9948 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9950
9951 /* mark variable to be irrelevant */
9952 irrelevants[v] = TRUE;
9953
9954 /* for the statistic we count the number of jobs which are irrelevant */
9956 }
9957 else if( lst <= hmin && SCIPconsIsChecked(cons) )
9958 {
9959 /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9960 * so the down lock can be omitted
9961 */
9962
9963 assert(downlocks != NULL);
9964 assert(uplocks != NULL);
9965
9966 if( !uplocks[v] )
9967 {
9968 /* the variables has no up lock and we can also remove the down lock;
9969 * => lst <= hmin and ect >= hmax
9970 * => remove job and reduce capacity by the demand of that job
9971 *
9972 * We mark the job to be deletable. The removement together with the capacity reducion is done later
9973 */
9974
9975 SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
9976 SCIPvarGetName(var), ect - duration, lst, duration);
9977
9978 /* mark variable to be irrelevant */
9979 irrelevants[v] = TRUE;
9980
9981 /* for the statistic we count the number of jobs which always run during the effective horizon */
9983 }
9984
9985 if( downlocks[v] )
9986 {
9987 SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
9989
9991 downlocks[v] = FALSE;
9992 (*nchgsides)++;
9993
9994 /* for the statistic we count the number of removed locks */
9996 }
9997 }
9998 else if( ect <= hmin )
9999 {
10000 /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10001 * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10002 * removed form the cumulative condition after it was fixed to its earliest start time
10003 */
10004
10005 /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10006 * bound;
10007 */
10008 if( downlocks != NULL && SCIPconsIsChecked(cons) )
10009 {
10010 /* fix integer start time variable if possible to it lower bound */
10011 SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10012 }
10013
10015 {
10016 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10017 SCIPvarGetName(var), ect - duration, lst, duration);
10018
10019 /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10021
10022 /* mark variable to be irrelevant */
10023 irrelevants[v] = TRUE;
10024
10025 /* for the statistic we count the number of jobs which are dual fixed */
10027 }
10028 }
10029 else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10030 {
10031 assert(downlocks != NULL);
10032
10033 /* check step (4) and (5) */
10034
10035 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10036 * is in favor of rounding the variable down
10037 */
10038 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10039 {
10040 SCIP_Bool roundable;
10041
10042 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10043
10044 if( roundable )
10045 {
10046 if( alternativelb > lst )
10047 {
10048 SCIP_Bool infeasible;
10049 SCIP_Bool fixed;
10050
10051 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10052 assert(!infeasible);
10053 assert(fixed);
10054
10055 (*nfixedvars)++;
10056
10057 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10058 * constraints
10059 */
10061 }
10062 else
10063 {
10064 SCIP_Bool success;
10065
10066 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10067 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10068 * infeasible we can apply the dual reduction; otherwise we do nothing
10069 */
10070 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10071 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10072 nfixedvars, &success, cutoff) );
10073
10074 if( success )
10075 {
10077 }
10078 }
10079 }
10080 }
10081 }
10082
10083 SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10085 }
10086
10087 /* free temporary memory */
10088 SCIPfreeBufferArray(scip, &uppropubs);
10089 SCIPfreeBufferArray(scip, &upproplbs);
10090 SCIPfreeBufferArray(scip, &upimplubs);
10091 SCIPfreeBufferArray(scip, &upimpllbs);
10092 SCIPfreeBufferArray(scip, &downpropubs);
10093 SCIPfreeBufferArray(scip, &downproplbs);
10094 SCIPfreeBufferArray(scip, &downimplubs);
10095 SCIPfreeBufferArray(scip, &downimpllbs);
10096
10097 return SCIP_OKAY;
10098}
10099
10100/** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10101 *
10102 * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10103 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10104 *
10105 * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10106 * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10107 * up-lock of the corresponding start time variable can be removed.
10108 *
10109 * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10110 * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10111 * positive, than the job can be dual fixed to its latest start time (lst).
10112 *
10113 * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10114 * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10115 * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10116 * of the corresponding job).
10117
10118 * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10119 * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10120 * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10121 * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10122 *
10123 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10124 * the cumulative condition; The deletion has to be done later.
10125 */
10126static
10128 SCIP* scip, /**< SCIP data structure */
10129 int nvars, /**< number of start time variables (activities) */
10130 SCIP_VAR** vars, /**< array of start time variables */
10131 int* durations, /**< array of durations */
10132 int hmin, /**< left bound of time axis to be considered (including hmin) */
10133 int hmax, /**< right bound of time axis to be considered (not including hmax) */
10134 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10135 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10136 SCIP_CONS* cons, /**< underlying constraint, or NULL */
10137 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10138 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10139 int* nchgsides, /**< pointer to store the number of changed sides */
10140 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10141 )
10142{
10143 SCIP_Real* downimpllbs;
10144 SCIP_Real* downimplubs;
10145 SCIP_Real* downproplbs;
10146 SCIP_Real* downpropubs;
10147 SCIP_Real* upimpllbs;
10148 SCIP_Real* upimplubs;
10149 SCIP_Real* upproplbs;
10150 SCIP_Real* uppropubs;
10151
10152 int firstmaxlst;
10153 int secondmaxlst;
10154 int v;
10155
10156 /* get temporary memory for storing probing results needed for step (4) and (5) */
10157 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10158 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10159 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10160 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10161 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10162 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10163 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10164 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10165
10166 assert(scip != NULL);
10167 assert(nvars > 1);
10168 assert(cons != NULL);
10169
10170 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10171
10172 firstmaxlst = INT_MIN;
10173 secondmaxlst = INT_MIN;
10174
10175 /* compute the two largest latest start times; which are needed for step (5) */
10176 for( v = 0; v < nvars; ++v )
10177 {
10178 int lst;
10179
10181
10182 if( lst > firstmaxlst )
10183 {
10184 secondmaxlst = firstmaxlst;
10185 firstmaxlst = lst;
10186 }
10187 else if( lst > secondmaxlst )
10188 secondmaxlst = lst;
10189 }
10190
10191 /* loop over all jobs and check if one of the 5 reductions can be applied */
10192 for( v = 0; v < nvars; ++v )
10193 {
10194 SCIP_VAR* var;
10195 int duration;
10196
10197 int alternativeub;
10198 int maxlst;
10199 int est;
10200 int ect;
10201 int lst;
10202
10203 var = vars[v];
10204 assert(var != NULL);
10205
10206 duration = durations[v];
10207 assert(duration > 0);
10208
10209 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10210 * time (lct)
10211 */
10213 ect = est + duration;
10215
10216 /* compute the latest start time of all remaining jobs */
10217 if( lst == firstmaxlst )
10218 maxlst = secondmaxlst;
10219 else
10220 maxlst = firstmaxlst;
10221
10222 /* compute potential alternative upper bound (step (4) and (5)) */
10223 alternativeub = MIN(hmax - 1, maxlst) - duration;
10224 alternativeub = MAX(alternativeub, hmin);
10225
10226 if( est >= hmax )
10227 {
10228 /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10229 * cumulative condition
10230 */
10231 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10233
10234 /* mark variable to be irrelevant */
10235 irrelevants[v] = TRUE;
10236
10237 /* for the statistic we count the number of jobs which are irrelevant */
10239 }
10240 else if( ect >= hmax && SCIPconsIsChecked(cons) )
10241 {
10242 assert(downlocks != NULL);
10243 assert(uplocks != NULL);
10244
10245 /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10246 * so the up lock can be omitted
10247 */
10248
10249 if( !downlocks[v] )
10250 {
10251 /* the variables has no down lock and we can also remove the up lock;
10252 * => lst <= hmin and ect >= hmax
10253 * => remove job and reduce capacity by the demand of that job
10254 */
10255 SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10256 SCIPvarGetName(var), est, lst, duration);
10257
10258 /* mark variable to be irrelevant */
10259 irrelevants[v] = TRUE;
10260
10261 /* for the statistic we count the number of jobs which always run during the effective horizon */
10263 }
10264
10265 if( uplocks[v] )
10266 {
10267 SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10269
10271 uplocks[v] = FALSE;
10272 (*nchgsides)++;
10273
10274 /* for the statistic we count the number of removed locks */
10276 }
10277 }
10278 else if( lst >= hmax )
10279 {
10280 /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10281 * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10282 * removed form the cumulative condition after it was fixed to its latest start time
10283 */
10284
10285 /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10286 * bound
10287 */
10288 if( uplocks != NULL && SCIPconsIsChecked(cons) )
10289 {
10290 /* fix integer start time variable if possible to its upper bound */
10291 SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10292 }
10293
10295 {
10296 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10297 SCIPvarGetName(var), est, lst, duration);
10298
10299 /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10301
10302 /* mark variable to be irrelevant */
10303 irrelevants[v] = TRUE;
10304
10305 /* for the statistic we count the number of jobs which are dual fixed */
10307 }
10308 }
10309 else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10310 {
10311 assert(uplocks != NULL);
10312
10313 /* check step (4) and (5) */
10314
10315 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10316 * is in favor of rounding the variable down
10317 */
10318 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10319 {
10320 SCIP_Bool roundable;
10321
10322 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10323
10324 if( roundable )
10325 {
10326 if( alternativeub < est )
10327 {
10328 SCIP_Bool infeasible;
10329 SCIP_Bool fixed;
10330
10331 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10332 assert(!infeasible);
10333 assert(fixed);
10334
10335 (*nfixedvars)++;
10336
10337 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10338 * constraints
10339 */
10341 }
10342 else
10343 {
10344 SCIP_Bool success;
10345
10346 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10347 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10348 * in infeasible we can apply the dual reduction; otherwise we do nothing
10349 */
10350 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10351 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10352 nfixedvars, &success, cutoff) );
10353
10354 if( success )
10355 {
10357 }
10358 }
10359 }
10360 }
10361 }
10362 }
10363
10364 /* free temporary memory */
10365 SCIPfreeBufferArray(scip, &uppropubs);
10366 SCIPfreeBufferArray(scip, &upproplbs);
10367 SCIPfreeBufferArray(scip, &upimplubs);
10368 SCIPfreeBufferArray(scip, &upimpllbs);
10369 SCIPfreeBufferArray(scip, &downpropubs);
10370 SCIPfreeBufferArray(scip, &downproplbs);
10371 SCIPfreeBufferArray(scip, &downimplubs);
10372 SCIPfreeBufferArray(scip, &downimpllbs);
10373
10374 return SCIP_OKAY;
10375}
10376
10377/** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10378static
10380 SCIP* scip, /**< SCIP data structure */
10381 SCIP_CONS* cons, /**< cumulative constraint */
10382 int* nfixedvars, /**< pointer to store the number of fixed variables */
10383 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10384 int* nchgsides, /**< pointer to store the number of changed sides */
10385 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10386 )
10387{
10388 SCIP_CONSDATA* consdata;
10389 SCIP_Bool* irrelevants;
10390 int nvars;
10391 int v;
10392
10393 assert(scip != NULL);
10394 assert(cons != NULL);
10395 assert(!(*cutoff));
10396
10397 consdata = SCIPconsGetData(cons);
10398 assert(consdata != NULL);
10399
10400 nvars = consdata->nvars;
10401
10402 if( nvars <= 1 )
10403 return SCIP_OKAY;
10404
10405 SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10406 BMSclearMemoryArray(irrelevants, nvars);
10407
10408 /* presolve constraint form the earlier start time point of view */
10409 SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10410 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10411 irrelevants, nfixedvars, nchgsides, cutoff) );
10412
10413 /* presolve constraint form the latest completion time point of view */
10414 SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10415 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10416 irrelevants, nfixedvars, nchgsides, cutoff) );
10417
10418 /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10419 * order to ensure a correct behaviour
10420 */
10421 for( v = nvars-1; v >= 0; --v )
10422 {
10423 if( irrelevants[v] )
10424 {
10425 SCIP_VAR* var;
10426 int ect;
10427 int lst;
10428
10429 var = consdata->vars[v];
10430 assert(var != NULL);
10431
10432 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10434
10435 /* check if the jobs runs completely during the effective horizon */
10436 if( lst <= consdata->hmin && ect >= consdata->hmax )
10437 {
10438 if( consdata->capacity < consdata->demands[v] )
10439 {
10440 *cutoff = TRUE;
10441 break;
10442 }
10443
10444 consdata->capacity -= consdata->demands[v];
10445 consdata->varbounds = FALSE;
10446 }
10447
10448 SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10449 (*nchgcoefs)++;
10450 }
10451 }
10452
10453 SCIPfreeBufferArray(scip, &irrelevants);
10454
10455 return SCIP_OKAY;
10456}
10457
10458/** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10459static
10461 SCIP* scip, /**< SCIP data structure */
10462 SCIP_CONSDATA* consdata, /**< constraint data */
10463 int* startindices, /**< permutation with rspect to the start times */
10464 int curtime, /**< current point in time */
10465 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10466 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10467 SCIP_Longint** demands, /**< pointer to array storing the demands */
10468 int* ndemands /**< pointer to store the number of different demands */
10469 )
10470{
10471 int startindex;
10472 int ncountedvars;
10473
10474 assert(demands != NULL);
10475 assert(ndemands != NULL);
10476
10477 ncountedvars = 0;
10478 startindex = nstarted - 1;
10479
10480 *ndemands = 0;
10481
10482 /* search for the (nstarted - nfinished) jobs which are active at curtime */
10483 while( nstarted - nfinished > ncountedvars )
10484 {
10485 SCIP_VAR* var;
10486 int endtime;
10487 int varidx;
10488
10489 /* collect job information */
10490 varidx = startindices[startindex];
10492
10493 var = consdata->vars[varidx];
10494 assert(var != NULL);
10495
10496 endtime = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10497
10498 /* check the end time of this job is larger than the curtime; in this case the job is still running */
10499 if( endtime > curtime )
10500 {
10501 if( consdata->demands[varidx] < consdata->capacity )
10502 {
10503 (*demands)[*ndemands] = consdata->demands[varidx];
10504 (*ndemands)++;
10505 }
10506 ncountedvars++;
10507 }
10508
10509 startindex--;
10510 }
10511}
10512
10513/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10514 * constraint
10515 */
10516static
10518 SCIP* scip, /**< SCIP data structure */
10519 SCIP_CONS* cons, /**< constraint to be checked */
10520 int* startindices, /**< permutation with rspect to the start times */
10521 int curtime, /**< current point in time */
10522 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10523 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10524 int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10525 )
10526{
10527 SCIP_CONSDATA* consdata;
10528 SCIP_Longint* demands;
10529 SCIP_Real* profits;
10530 int* items;
10531 int ndemands;
10532 SCIP_Bool success;
10533 SCIP_Real solval;
10534 int j;
10535 assert(nstarted > nfinished);
10536
10537 consdata = SCIPconsGetData(cons);
10538 assert(consdata != NULL);
10539 assert(consdata->nvars > 0);
10540 assert(consdata->capacity > 0);
10541
10542 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10543 ndemands = 0;
10544
10545 /* get demand array to initialize knapsack problem */
10546 collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10547
10548 /* create array for profits */
10549 SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10550 SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10551 for( j = 0; j < ndemands; ++j )
10552 {
10553 profits[j] = (SCIP_Real) demands[j];
10554 items[j] = j;/* this is only a dummy value*/
10555 }
10556
10557 /* solve knapsack problem and get maximum capacity usage <= capacity */
10558 SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10559 items, NULL, NULL, NULL, NULL, &solval, &success) );
10560
10561 assert(SCIPisFeasIntegral(scip, solval));
10562
10563 /* store result */
10564 *bestcapacity = boundedConvertRealToInt(scip, solval);
10565
10566 SCIPfreeBufferArray(scip, &items);
10567 SCIPfreeBufferArray(scip, &profits);
10568 SCIPfreeBufferArray(scip, &demands);
10569
10570 return SCIP_OKAY;
10571}
10572
10573/** try to tighten the capacity
10574 * -- using DP for knapsack, we find the maximum possible capacity usage
10575 * -- neglects hmin and hmax, such that it is also able to check solutions globally
10576 */
10577static
10579 SCIP* scip, /**< SCIP data structure */
10580 SCIP_CONS* cons, /**< cumulative constraint */
10581 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10582 int* nchgsides /**< pointer to store the number of changed sides */
10583 )
10584{
10585 SCIP_CONSDATA* consdata;
10586 int* starttimes; /* stores when each job is starting */
10587 int* endtimes; /* stores when each job ends */
10588 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10589 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10590
10591 int nvars; /* number of activities for this constraint */
10592 int freecapacity; /* remaining capacity */
10593 int curtime; /* point in time which we are just checking */
10594 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10595
10596 int bestcapacity;
10597
10598 int j;
10599
10600 assert(scip != NULL);
10601 assert(cons != NULL);
10602 assert(nchgsides != NULL);
10603
10604 consdata = SCIPconsGetData(cons);
10605 assert(consdata != NULL);
10606
10607 nvars = consdata->nvars;
10608
10609 /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10610 if( nvars <= 1 || consdata->capacity <= 1 )
10611 return SCIP_OKAY;
10612
10613 assert(consdata->vars != NULL);
10614
10615 SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10616 SCIPconsGetName(cons), consdata->capacity);
10617
10618 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10619 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10620 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10621 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10622
10623 /* create event point arrays */
10624 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10625 starttimes, endtimes, startindices, endindices, FALSE);
10626
10627 bestcapacity = 1;
10628 endindex = 0;
10629 freecapacity = consdata->capacity;
10630
10631 /* check each startpoint of a job whether the capacity is kept or not */
10632 for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10633 {
10634 curtime = starttimes[j];
10635 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10636
10637 /* remove the capacity requirments for all job which start at the curtime */
10638 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10639
10640 /* add the capacity requirments for all job which end at the curtime */
10641 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10642
10643 assert(freecapacity <= consdata->capacity);
10644 assert(endindex <= nvars);
10645
10646 /* endindex - points to the next job which will finish */
10647 /* j - points to the last job that has been released */
10648
10649 /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10650 if( freecapacity < 0 )
10651 {
10652 int newcapacity;
10653
10654 newcapacity = 1;
10655
10656 /* get best possible upper bound on capacity usage */
10657 SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10658
10659 /* update bestcapacity */
10660 bestcapacity = MAX(bestcapacity, newcapacity);
10661 SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10662 }
10663
10664 /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10665 if( freecapacity > 0 && freecapacity != consdata->capacity )
10666 {
10667 bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10668 SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10669 }
10670
10671 /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10672 if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10673 {
10674 /* if demands[startindices[j]] == cap then exactly that job is running */
10675 SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10676 bestcapacity = consdata->capacity;
10677 break;
10678 }
10679 } /*lint --e{850}*/
10680
10681 /* free all buffer arrays */
10682 SCIPfreeBufferArray(scip, &endindices);
10683 SCIPfreeBufferArray(scip, &startindices);
10684 SCIPfreeBufferArray(scip, &endtimes);
10685 SCIPfreeBufferArray(scip, &starttimes);
10686
10687 /* check whether capacity can be tightened and whether demands need to be adjusted */
10688 if( bestcapacity < consdata->capacity )
10689 {
10690 SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10691
10692 SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10693 SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10694
10695 for( j = 0; j < nvars; ++j )
10696 {
10697 if( consdata->demands[j] == consdata->capacity )
10698 {
10699 consdata->demands[j] = bestcapacity;
10700 (*nchgcoefs)++;
10701 }
10702 }
10703
10704 consdata->capacity = bestcapacity;
10705 (*nchgsides)++;
10706
10707 SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10708
10709 consdata->varbounds = FALSE;
10710 }
10711
10712 return SCIP_OKAY;
10713}
10714
10715
10716/** tries to change coefficients:
10717 * demand_j < cap && all other parallel jobs in conflict
10718 * ==> set demand_j := cap
10719 */
10720static
10722 SCIP* scip, /**< SCIP data structure */
10723 SCIP_CONS* cons, /**< cumulative constraint */
10724 int* nchgcoefs /**< pointer to count total number of changed coefficients */
10725 )
10726{
10727 SCIP_CONSDATA* consdata;
10728 int nvars;
10729 int j;
10730 int oldnchgcoefs;
10731 int mindemand;
10732
10733 assert(scip != NULL);
10734 assert(cons != NULL);
10735 assert(nchgcoefs != NULL);
10736
10737 /* get constraint data for some parameter testings only! */
10738 consdata = SCIPconsGetData(cons);
10739 assert(consdata != NULL);
10740
10741 nvars = consdata->nvars;
10742 oldnchgcoefs = *nchgcoefs;
10743
10744 if( nvars <= 0 )
10745 return SCIP_OKAY;
10746
10747 /* PRE1:
10748 * check all jobs j whether: r_j + r_min > capacity holds
10749 * if so: adjust r_j to capacity
10750 */
10751 mindemand = consdata->demands[0];
10752 for( j = 0; j < nvars; ++j )
10753 {
10754 mindemand = MIN(mindemand, consdata->demands[j]);
10755 }
10756
10757 /*check each job */
10758 for( j = 0; j < nvars; ++j )
10759 {
10760 if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10761 {
10762 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10763 consdata->demands[j], consdata->capacity);
10764 consdata->demands[j] = consdata->capacity;
10765 (*nchgcoefs)++;
10766 }
10767 }
10768
10769 /* PRE2:
10770 * check for each job (with d_j < cap)
10771 * whether it is disjunctive to all others over the time horizon
10772 */
10773 for( j = 0; j < nvars; ++j )
10774 {
10775 SCIP_Bool chgcoef;
10776 int est_j;
10777 int lct_j;
10778 int i;
10779
10780 assert(consdata->demands[j] <= consdata->capacity);
10781
10782 if( consdata->demands[j] == consdata->capacity )
10783 continue;
10784
10785 chgcoef = TRUE;
10786
10787 est_j = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10788 lct_j = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10789
10790 for( i = 0; i < nvars; ++i )
10791 {
10792 int est_i;
10793 int lct_i;
10794
10795 if( i == j )
10796 continue;
10797
10798 est_i = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10799 lct_i = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10800
10801 if( est_i >= lct_j || est_j >= lct_i )
10802 continue;
10803
10804 if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10805 {
10806 chgcoef = FALSE;
10807 break;
10808 }
10809 }
10810
10811 if( chgcoef )
10812 {
10813 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10814 consdata->demands[j], consdata->capacity);
10815 consdata->demands[j] = consdata->capacity;
10816 (*nchgcoefs)++;
10817 }
10818 }
10819
10820 if( (*nchgcoefs) > oldnchgcoefs )
10821 {
10822 SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10823 (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10824 }
10825
10826 return SCIP_OKAY;
10827}
10828
10829#ifdef SCIP_DISABLED_CODE
10830/* The following should work, but does not seem to be tested well. */
10831
10832/** try to reformulate constraint by replacing certain jobs */
10833static
10834SCIP_RETCODE reformulateCons(
10835 SCIP* scip, /**< SCIP data structure */
10836 SCIP_CONS* cons, /**< cumulative constraint */
10837 int* naggrvars /**< pointer to store the number of aggregated variables */
10838 )
10839{
10840 SCIP_CONSDATA* consdata;
10841 int hmin;
10842 int hmax;
10843 int nvars;
10844 int v;
10845
10846 consdata = SCIPconsGetData(cons);
10847 assert(cons != NULL);
10848
10849 nvars = consdata->nvars;
10850 assert(nvars > 1);
10851
10852 hmin = consdata->hmin;
10853 hmax = consdata->hmax;
10854 assert(hmin < hmax);
10855
10856 for( v = 0; v < nvars; ++v )
10857 {
10858 SCIP_VAR* var;
10859 int duration;
10860 int est;
10861 int ect;
10862 int lst;
10863 int lct;
10864
10865 var = consdata->vars[v];
10866 assert(var != NULL);
10867
10868 duration = consdata->durations[v];
10869
10871 ect = est + duration;
10873 lct = lst + duration;
10874
10875 /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10876 assert(lst > hmin || ect < hmax);
10877
10878 if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10879 {
10880 SCIP_VAR* aggrvar;
10881 char name[SCIP_MAXSTRLEN];
10882 SCIP_Bool infeasible;
10883 SCIP_Bool redundant;
10884 SCIP_Bool aggregated;
10885 int shift;
10886
10887 shift = est - (hmin - lct + MIN(hmin, ect));
10888 assert(shift > 0);
10889 lst = hmin;
10890 duration = hmin - lct;
10891
10892 SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10894
10895 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10896 SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10899 SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10900
10901 assert(!infeasible);
10902 assert(!redundant);
10903 assert(aggregated);
10904
10905 /* replace variable */
10906 consdata->durations[v] = duration;
10907 consdata->vars[v] = aggrvar;
10908
10909 /* remove and add locks */
10910 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10911 SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10912
10913 SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10914
10915 (*naggrvars)++;
10916 }
10917 }
10918
10919 return SCIP_OKAY;
10920}
10921#endif
10922
10923/** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10924static
10926 SCIP* scip, /**< SCIP data structure */
10927 SCIP_CONS* cons, /**< cumulative constraint */
10928 int* naddconss /**< pointer to store the number of added constraints */
10929 )
10930{
10931 SCIP_CONSDATA* consdata;
10932 SCIP_VAR** vars;
10933 int* durations;
10934 int* demands;
10935 int capacity;
10936 int halfcapacity;
10937 int mindemand;
10938 int nvars;
10939 int v;
10940
10941 consdata = SCIPconsGetData(cons);
10942 assert(consdata != NULL);
10943
10944 capacity = consdata->capacity;
10945
10946 if( capacity == 1 )
10947 return SCIP_OKAY;
10948
10949 SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10950 SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10951 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10952
10953 halfcapacity = capacity / 2;
10954 mindemand = consdata->capacity;
10955 nvars = 0;
10956
10957 /* collect all jobs with demand larger than half of the capacity */
10958 for( v = 0; v < consdata->nvars; ++v )
10959 {
10960 if( consdata->demands[v] > halfcapacity )
10961 {
10962 vars[nvars] = consdata->vars[v];
10963 demands[nvars] = 1;
10964 durations[nvars] = consdata->durations[v];
10965 nvars++;
10966
10967 mindemand = MIN(mindemand, consdata->demands[v]);
10968 }
10969 }
10970
10971 if( nvars > 0 )
10972 {
10973 /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
10974 * job is still to large to be scheduled in parallel
10975 */
10976 for( v = 0; v < consdata->nvars; ++v )
10977 {
10978 if( consdata->demands[v] > halfcapacity )
10979 continue;
10980
10981 if( mindemand + consdata->demands[v] > capacity )
10982 {
10983 demands[nvars] = 1;
10984 durations[nvars] = consdata->durations[v];
10985 vars[nvars] = consdata->vars[v];
10986 nvars++;
10987
10988 /* @todo create one cumulative constraint and look for another small demand */
10989 break;
10990 }
10991 }
10992
10993 /* creates cumulative constraint and adds it to problem */
10994 SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
10996 (*naddconss)++;
10997 }
10998
10999 SCIPfreeBufferArray(scip, &demands);
11000 SCIPfreeBufferArray(scip, &durations);
11002
11003 return SCIP_OKAY;
11004}
11005
11006/** presolve given constraint */
11007static
11009 SCIP* scip, /**< SCIP data structure */
11010 SCIP_CONS* cons, /**< cumulative constraint */
11011 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11012 SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11013 int* nfixedvars, /**< pointer to store the number of fixed variables */
11014 int* nchgbds, /**< pointer to store the number of changed bounds */
11015 int* ndelconss, /**< pointer to store the number of deleted constraints */
11016 int* naddconss, /**< pointer to store the number of added constraints */
11017 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11018 int* nchgsides, /**< pointer to store the number of changed sides */
11019 SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11020 SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11021 )
11022{
11023 assert(!SCIPconsIsDeleted(cons));
11024
11025 /* only perform dual reductions on model constraints */
11026 if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11027 {
11028 /* computes the effective horizon and checks if the constraint can be decomposed */
11029 SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11030
11031 if( SCIPconsIsDeleted(cons) )
11032 return SCIP_OKAY;
11033
11034 /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11035 * fixings (dual reductions)
11036 */
11037 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11038 {
11039 SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11040
11041 if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11042 return SCIP_OKAY;
11043 }
11044
11045 SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11046
11047 if( *cutoff || SCIPconsIsDeleted(cons) )
11048 return SCIP_OKAY;
11049 }
11050
11051 /* remove jobs which have a demand larger than the capacity */
11052 SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11053 assert((*cutoff) || checkDemands(scip, cons));
11054
11055 if( *cutoff )
11056 return SCIP_OKAY;
11057
11058 if( conshdlrdata->normalize )
11059 {
11060 /* divide demands by their greatest common divisor */
11061 normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11062 }
11063
11064 /* delete constraint with one job */
11065 SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11066
11067 if( *cutoff || SCIPconsIsDeleted(cons) )
11068 return SCIP_OKAY;
11069
11070 if( conshdlrdata->coeftightening )
11071 {
11072 /* try to tighten the capacity */
11073 SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11074
11075 /* try to tighten the coefficients */
11076 SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11077 }
11078
11079 assert(checkDemands(scip, cons) || *cutoff);
11080
11081#ifdef SCIP_DISABLED_CODE
11082 /* The following should work, but does not seem to be tested well. */
11083 SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11084#endif
11085
11086 return SCIP_OKAY;
11087}
11088
11089/**@name TClique Graph callbacks
11090 *
11091 * @{
11092 */
11093
11094/** tclique graph data */
11095struct TCLIQUE_Graph
11096{
11097 SCIP_VAR** vars; /**< start time variables each of them is a node */
11098 SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11099 SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11100 SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11101 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11102 int* ninarcs; /**< number if in arcs for the precedence graph */
11103 int* noutarcs; /**< number if out arcs for the precedence graph */
11104 int* durations; /**< for each node the duration of the corresponding job */
11105 int nnodes; /**< number of nodes */
11106 int size; /**< size of the array */
11107};
11108
11109/** gets number of nodes in the graph */
11110static
11111TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11112{
11113 assert(tcliquegraph != NULL);
11114
11115 return tcliquegraph->nnodes;
11116}
11117
11118/** gets weight of nodes in the graph */
11119static
11120TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11121{
11122 assert(tcliquegraph != NULL);
11123
11124 return tcliquegraph->weights;
11125}
11126
11127/** returns, whether the edge (node1, node2) is in the graph */
11128static
11129TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11130{
11131 assert(tcliquegraph != NULL);
11132 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11133 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11134
11135 /* check if an arc exits in the precedence graph */
11136 if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11137 return TRUE;
11138
11139 /* check if an edge exits in the non-overlapping graph */
11140 if( tcliquegraph->demandmatrix[node1][node2] )
11141 return TRUE;
11142
11143 return FALSE;
11144}
11145
11146/** selects all nodes from a given set of nodes which are adjacent to a given node
11147 * and returns the number of selected nodes
11148 */
11149static
11150TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11151{
11152 int nadjnodes;
11153 int i;
11154
11155 assert(tcliquegraph != NULL);
11156 assert(0 <= node && node < tcliquegraph->nnodes);
11157 assert(nnodes == 0 || nodes != NULL);
11158 assert(adjnodes != NULL);
11159
11160 nadjnodes = 0;
11161
11162 for( i = 0; i < nnodes; i++ )
11163 {
11164 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11165 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11166 assert(i == 0 || nodes[i-1] < nodes[i]);
11167
11168 /* check if an edge exists */
11169 if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11170 {
11171 /* current node is adjacent to given node */
11172 adjnodes[nadjnodes] = nodes[i];
11173 nadjnodes++;
11174 }
11175 }
11176
11177 return nadjnodes;
11178}
11179
11180/** generates cuts using a clique found by algorithm for maximum weight clique
11181 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11182 */
11183static
11184TCLIQUE_NEWSOL(tcliqueNewsolClique)
11185{ /*lint --e{715}*/
11186 SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11187}
11188
11189
11190/** @} */
11191
11192/** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11193 * job corresponding to variable bound variable (vlbvar)
11194 *
11195 * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11196 */
11197static
11199 SCIP* scip, /**< SCIP data structure */
11200 SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11201 SCIP_Real vlbcoef, /**< variable bound coefficient */
11202 SCIP_Real vlbconst, /**< variable bound constant */
11203 int duration /**< duration of the variable bound variable */
11204 )
11205{
11206 if( SCIPisEQ(scip, vlbcoef, 1.0) )
11207 {
11208 if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11209 {
11210 /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11211 return TRUE;
11212 }
11213 }
11214 else
11215 {
11217
11218 bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11219
11220 if( SCIPisLT(scip, vlbcoef, 1.0) )
11221 {
11222 SCIP_Real ub;
11223
11224 ub = SCIPvarGetUbLocal(vlbvar);
11225
11226 /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11227 if( SCIPisLE(scip, ub, bound) )
11228 return TRUE;
11229 }
11230 else
11231 {
11232 SCIP_Real lb;
11233
11234 assert(SCIPisGT(scip, vlbcoef, 1.0));
11235
11236 lb = SCIPvarGetLbLocal(vlbvar);
11237
11238 /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11239 if( SCIPisGE(scip, lb, bound) )
11240 return TRUE;
11241 }
11242 }
11243
11244 return FALSE;
11245}
11246
11247/** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11248 * job corresponding to variable which is bounded (var)
11249 *
11250 * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11251 */
11252static
11254 SCIP* scip, /**< SCIP data structure */
11255 SCIP_VAR* var, /**< variable which is bound from above */
11256 SCIP_Real vubcoef, /**< variable bound coefficient */
11257 SCIP_Real vubconst, /**< variable bound constant */
11258 int duration /**< duration of the variable which is bounded from above */
11259 )
11260{
11261 SCIP_Real vlbcoef;
11262 SCIP_Real vlbconst;
11263
11264 /* convert the variable upper bound into an variable lower bound */
11265 vlbcoef = 1.0 / vubcoef;
11266 vlbconst = -vubconst / vubcoef;
11267
11268 return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11269}
11270
11271/** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11272 * others an index larger than the number if active variables
11273 */
11274static
11276 SCIP* scip, /**< SCIP data structure */
11277 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11278 SCIP_VAR* var, /**< variable for which we want the index */
11279 int* idx /**< pointer to store the index */
11280 )
11281{
11282 (*idx) = SCIPvarGetProbindex(var);
11283
11284 if( (*idx) == -1 )
11285 {
11286 if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11287 {
11288 (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11289 }
11290 else
11291 {
11292 int pos;
11293 int v;
11294
11295 /**@todo we might want to add the aggregation path to graph */
11296
11297 /* check if we have to realloc memory */
11298 if( tcliquegraph->size == tcliquegraph->nnodes )
11299 {
11300 int size;
11301
11302 size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11303 tcliquegraph->size = size;
11304
11305 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11306 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11307 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11308 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11309 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11310
11311 for( v = 0; v < tcliquegraph->nnodes; ++v )
11312 {
11313 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11314 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11315 }
11316 }
11317 assert(tcliquegraph->nnodes < tcliquegraph->size);
11318
11319 pos = tcliquegraph->nnodes;
11320 assert(pos >= 0);
11321
11322 tcliquegraph->durations[pos] = 0;
11323 tcliquegraph->weights[pos] = 0;
11324 tcliquegraph->vars[pos] = var;
11325
11326 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11327 BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11328
11329 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11330 BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11331
11332 SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11333
11334 tcliquegraph->nnodes++;
11335
11336 for( v = 0; v < tcliquegraph->nnodes; ++v )
11337 {
11338 tcliquegraph->precedencematrix[v][pos] = 0;
11339 tcliquegraph->demandmatrix[v][pos] = 0;
11340 }
11341
11342 (*idx) = tcliquegraph->nnodes;
11343 }
11344 }
11345 else
11346 {
11347 assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11348 }
11349
11350 assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11351
11352 return SCIP_OKAY;
11353}
11354
11355/** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11356 *
11357 * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11358 * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11359 *
11360 * (i) b = 1 and c >= d
11361 * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11362 * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11363 *
11364 */
11365static
11367 SCIP* scip, /**< SCIP data structure */
11368 TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11369 )
11370{
11371 SCIP_VAR** vars;
11372 int nvars;
11373 int v;
11374
11377
11378 /* try to project each arc of the variable bound graph to precedence condition */
11379 for( v = 0; v < nvars; ++v )
11380 {
11381 SCIP_VAR** vbdvars;
11382 SCIP_VAR* var;
11383 SCIP_Real* vbdcoefs;
11384 SCIP_Real* vbdconsts;
11385 int nvbdvars;
11386 int idx1;
11387 int b;
11388
11389 var = vars[v];
11390 assert(var != NULL);
11391
11392 SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11393 assert(idx1 >= 0);
11394
11395 if( tcliquegraph->durations[idx1] == 0 )
11396 continue;
11397
11398 vbdvars = SCIPvarGetVlbVars(var);
11399 vbdcoefs = SCIPvarGetVlbCoefs(var);
11400 vbdconsts = SCIPvarGetVlbConstants(var);
11401 nvbdvars = SCIPvarGetNVlbs(var);
11402
11403 for( b = 0; b < nvbdvars; ++b )
11404 {
11405 int idx2;
11406
11407 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11408 assert(idx2 >= 0);
11409
11410 if( tcliquegraph->durations[idx2] == 0 )
11411 continue;
11412
11413 if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11414 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11415 }
11416
11417 vbdvars = SCIPvarGetVubVars(var);
11418 vbdcoefs = SCIPvarGetVubCoefs(var);
11419 vbdconsts = SCIPvarGetVubConstants(var);
11420 nvbdvars = SCIPvarGetNVubs(var);
11421
11422 for( b = 0; b < nvbdvars; ++b )
11423 {
11424 int idx2;
11425
11426 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11427 assert(idx2 >= 0);
11428
11429 if( tcliquegraph->durations[idx2] == 0 )
11430 continue;
11431
11432 if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11433 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11434 }
11435
11436 for( b = v+1; b < nvars; ++b )
11437 {
11438 int idx2;
11439
11440 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11441 assert(idx2 >= 0);
11442
11443 if( tcliquegraph->durations[idx2] == 0 )
11444 continue;
11445
11446 /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11447 if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11448 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11449
11450 /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11451 if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11452 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11453 }
11454 }
11455
11456 return SCIP_OKAY;
11457}
11458
11459/** compute the transitive closer of the given graph and the number of in and out arcs */
11460static
11462 SCIP_Bool** adjmatrix, /**< adjacent matrix */
11463 int* ninarcs, /**< array to store the number of in arcs */
11464 int* noutarcs, /**< array to store the number of out arcs */
11465 int nnodes /**< number if nodes */
11466 )
11467{
11468 int i;
11469 int j;
11470 int k;
11471
11472 for( i = 0; i < nnodes; ++i )
11473 {
11474 for( j = 0; j < nnodes; ++j )
11475 {
11476 if( adjmatrix[i][j] )
11477 {
11478 ninarcs[j]++;
11479 noutarcs[i]++;
11480
11481 for( k = 0; k < nnodes; ++k )
11482 {
11483 if( adjmatrix[j][k] )
11484 adjmatrix[i][k] = TRUE;
11485 }
11486 }
11487 }
11488 }
11489}
11490
11491/** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11492static
11494 SCIP* scip, /**< SCIP data structure */
11495 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11496 SCIP_CONS** conss, /**< array of cumulative constraints */
11497 int nconss /**< number of cumulative constraints */
11498 )
11499{
11500 int c;
11501
11502 /* use the cumulative constraints to initialize the none overlapping graph */
11503 for( c = 0; c < nconss; ++c )
11504 {
11505 SCIP_CONSDATA* consdata;
11506 SCIP_VAR** vars;
11507 int* demands;
11508 int capacity;
11509 int nvars;
11510 int i;
11511
11512 consdata = SCIPconsGetData(conss[c]);
11513 assert(consdata != NULL);
11514
11515 vars = consdata->vars;
11516 demands = consdata->demands;
11517
11518 nvars = consdata->nvars;
11519 capacity = consdata->capacity;
11520
11521 SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11522
11523 /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11524 for( i = 0; i < nvars; ++i )
11525 {
11526 int idx1;
11527 int j;
11528
11529 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11530 assert(idx1 >= 0);
11531
11532 if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11533 continue;
11534
11535 for( j = i+1; j < nvars; ++j )
11536 {
11537 assert(consdata->durations[j] > 0);
11538
11539 if( demands[i] + demands[j] > capacity )
11540 {
11541 int idx2;
11542 int est1;
11543 int est2;
11544 int lct1;
11545 int lct2;
11546
11547 /* check if the effective horizon is large enough */
11550
11551 /* at least one of the jobs needs to start at hmin or later */
11552 if( est1 < consdata->hmin && est2 < consdata->hmin )
11553 continue;
11554
11555 lct1 = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11556 lct2 = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11557
11558 /* at least one of the jobs needs to finish not later then hmin */
11559 if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11560 continue;
11561
11562 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11563 assert(idx2 >= 0);
11564 assert(idx1 != idx2);
11565
11566 if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11567 continue;
11568
11569 SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11570
11571 assert(tcliquegraph->durations[idx1] > 0);
11572 assert(tcliquegraph->durations[idx2] > 0);
11573
11574 tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11575 tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11576 }
11577 }
11578 }
11579 }
11580
11581 return SCIP_OKAY;
11582}
11583
11584/** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11585 * of jobs cannot run in parallel
11586 */
11587static
11589 SCIP* scip, /**< SCIP data structure */
11590 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11591 SCIP_CONS** conss, /**< array of cumulative constraints */
11592 int nconss /**< number of cumulative constraints */
11593 )
11594{
11595 assert(scip != NULL);
11596 assert(tcliquegraph != NULL);
11597
11598 /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11599 SCIP_CALL( projectVbd(scip, tcliquegraph) );
11600
11601 /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11602 transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11603
11604 /* constraints non-overlapping graph */
11605 SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11606
11607 return SCIP_OKAY;
11608}
11609
11610/** create cumulative constraint from conflict set */
11611static
11613 SCIP* scip, /**< SCIP data structure */
11614 const char* name, /**< constraint name */
11615 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11616 int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11617 int ncliquenodes /**< number of nodes in the clique */
11618 )
11619{
11620 SCIP_CONS* cons;
11621 SCIP_VAR** vars;
11622 int* durations;
11623 int* demands;
11624 int v;
11625
11626 SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11627 SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11628 SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11629
11630 SCIPsortInt(cliquenodes, ncliquenodes);
11631
11632 /* collect variables, durations, and demands */
11633 for( v = 0; v < ncliquenodes; ++v )
11634 {
11635 durations[v] = tcliquegraph->durations[cliquenodes[v]];
11636 assert(durations[v] > 0);
11637 demands[v] = 1;
11638 vars[v] = tcliquegraph->vars[cliquenodes[v]];
11639 }
11640
11641 /* create (unary) cumulative constraint */
11642 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11644
11645 SCIP_CALL( SCIPaddCons(scip, cons) );
11646 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11647
11648 /* free buffers */
11649 SCIPfreeBufferArray(scip, &demands);
11650 SCIPfreeBufferArray(scip, &durations);
11652
11653 return SCIP_OKAY;
11654}
11655
11656/** search for cumulative constrainst */
11657static
11659 SCIP* scip, /**< SCIP data structure */
11660 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11661 int* naddconss /**< pointer to store the number of added constraints */
11662 )
11663{
11664 TCLIQUE_STATUS tcliquestatus;
11665 SCIP_Bool* precedencerow;
11666 SCIP_Bool* precedencecol;
11667 SCIP_Bool* demandrow;
11668 SCIP_Bool* demandcol;
11669 SCIP_HASHTABLE* covered;
11670 int* cliquenodes;
11671 int ncliquenodes;
11672 int cliqueweight;
11673 int ntreenodes;
11674 int nnodes;
11675 int nconss;
11676 int v;
11677
11678 nnodes = tcliquegraph->nnodes;
11679 nconss = 0;
11680
11681 /* initialize the weight of each job with its duration */
11682 for( v = 0; v < nnodes; ++v )
11683 {
11684 tcliquegraph->weights[v] = tcliquegraph->durations[v];
11685 }
11686
11687 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11688 SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11689 SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11690 SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11691 SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11692
11693 /* create a hash table to store all start time variables which are already covered by at least one clique */
11695 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11696
11697 /* for each variables/job we are ... */
11698 for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11699 {
11700 char name[SCIP_MAXSTRLEN];
11701 int c;
11702
11703 /* jobs with zero durations are skipped */
11704 if( tcliquegraph->durations[v] == 0 )
11705 continue;
11706
11707 /* check if the start time variable is already covered by at least one clique */
11708 if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11709 continue;
11710
11711 SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11712
11713 /* temporarily remove the connection via the precedence graph */
11714 for( c = 0; c < nnodes; ++c )
11715 {
11716 precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11717 precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11718
11719 demandrow[c] = tcliquegraph->demandmatrix[v][c];
11720 demandcol[c] = tcliquegraph->demandmatrix[c][v];
11721
11722 tcliquegraph->precedencematrix[c][v] = FALSE;
11723 tcliquegraph->precedencematrix[v][c] = FALSE;
11724 }
11725
11726 /* find (heuristically) maximum cliques which includes node v */
11727 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11728 tcliquegraph, tcliqueNewsolClique, NULL,
11729 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11730 10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11731
11732 SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11733
11734 if( ncliquenodes == 1 )
11735 continue;
11736
11737 /* construct constraint name */
11738 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11739
11740 SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11741 nconss++;
11742
11743 /* all start time variable to covered hash table */
11744 for( c = 0; c < ncliquenodes; ++c )
11745 {
11746 SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11747 }
11748
11749 /* copy the precedence relations back */
11750 for( c = 0; c < nnodes; ++c )
11751 {
11752 tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11753 tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11754
11755 tcliquegraph->demandmatrix[v][c] = demandrow[c];
11756 tcliquegraph->demandmatrix[c][v] = demandcol[c];
11757 }
11758 }
11759
11760 SCIPhashtableFree(&covered);
11761
11762 SCIPfreeBufferArray(scip, &demandcol);
11763 SCIPfreeBufferArray(scip, &demandrow);
11764 SCIPfreeBufferArray(scip, &precedencecol);
11765 SCIPfreeBufferArray(scip, &precedencerow);
11766 SCIPfreeBufferArray(scip, &cliquenodes);
11767
11768 (*naddconss) += nconss;
11769
11770 /* for the statistic we count the number added disjunctive constraints */
11771 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11772
11773 return SCIP_OKAY;
11774}
11775
11776/** create precedence constraint (as variable bound constraint */
11777static
11779 SCIP* scip, /**< SCIP data structure */
11780 const char* name, /**< constraint name */
11781 SCIP_VAR* var, /**< variable x that has variable bound */
11782 SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11783 int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11784 )
11785{
11786 SCIP_CONS* cons;
11787
11788 /* create variable bound constraint */
11789 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11791
11793
11794 /* add constraint to problem and release it */
11795 SCIP_CALL( SCIPaddCons(scip, cons) );
11796 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11797
11798 return SCIP_OKAY;
11799}
11800
11801/** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11802static
11804 SCIP* scip, /**< SCIP data structure */
11805 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11806 int source, /**< index of the source node */
11807 int sink, /**< index of the sink node */
11808 int* naddconss /**< pointer to store the number of added constraints */
11809 )
11810{
11811 TCLIQUE_WEIGHT cliqueweight;
11812 TCLIQUE_STATUS tcliquestatus;
11813 SCIP_VAR** vars;
11814 int* cliquenodes;
11815 int nnodes;
11816 int lct;
11817 int est;
11818 int i;
11819
11820 int ntreenodes;
11821 int ncliquenodes;
11822
11823 /* check if source and sink are connencted */
11824 if( !tcliquegraph->precedencematrix[source][sink] )
11825 return SCIP_OKAY;
11826
11827 nnodes = tcliquegraph->nnodes;
11828 vars = tcliquegraph->vars;
11829
11830 /* reset the weights to zero */
11831 BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11832
11833 /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11834 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11836
11837 /* weight all jobs which run for sure between source and sink with their duration */
11838 for( i = 0; i < nnodes; ++i )
11839 {
11840 SCIP_VAR* var;
11841 int duration;
11842
11843 var = vars[i];
11844 assert(var != NULL);
11845
11846 duration = tcliquegraph->durations[i];
11847
11848 if( i == source || i == sink )
11849 {
11850 /* source and sink are not weighted */
11851 tcliquegraph->weights[i] = 0;
11852 }
11853 else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11854 {
11855 /* job i runs after source and before sink */
11856 tcliquegraph->weights[i] = duration;
11857 }
11859 && est >= boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11860 {
11861 /* job i run in between due the bounds of the start time variables */
11862 tcliquegraph->weights[i] = duration;
11863 }
11864 else
11865 tcliquegraph->weights[i] = 0;
11866 }
11867
11868 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11869
11870 /* find (heuristically) maximum cliques */
11871 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11872 tcliquegraph, tcliqueNewsolClique, NULL,
11873 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11874 10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11875
11876 if( ncliquenodes > 1 )
11877 {
11878 char name[SCIP_MAXSTRLEN];
11879 int distance;
11880
11881 /* construct constraint name */
11882 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11883
11884 /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11885 * duration of the source job
11886 */
11887 distance = cliqueweight + tcliquegraph->durations[source];
11888
11889 SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11890 (*naddconss)++;
11891 }
11892
11893 SCIPfreeBufferArray(scip, &cliquenodes);
11894
11895 return SCIP_OKAY;
11896}
11897
11898/** search for precedence constraints
11899 *
11900 * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11901 * corresponding two jobs
11902 */
11903static
11905 SCIP* scip, /**< SCIP data structure */
11906 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11907 int* naddconss /**< pointer to store the number of added constraints */
11908 )
11909{
11910 int* sources;
11911 int* sinks;
11912 int nconss;
11913 int nnodes;
11914 int nsources;
11915 int nsinks;
11916 int i;
11917
11918 nnodes = tcliquegraph->nnodes;
11919 nconss = 0;
11920
11921 nsources = 0;
11922 nsinks = 0;
11923
11926
11927 /* first collect all sources and sinks */
11928 for( i = 0; i < nnodes; ++i )
11929 {
11930 if( tcliquegraph->ninarcs[i] == 0 )
11931 {
11932 sources[nsources] = i;
11933 nsources++;
11934 }
11935
11936 if( tcliquegraph->noutarcs[i] == 0 )
11937 {
11938 sinks[nsinks] = i;
11939 nsinks++;
11940 }
11941 }
11942
11943 /* compute for each node a minimum distance to each sources and each sink */
11944 for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
11945 {
11946 int j;
11947
11948 for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
11949 {
11950 SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
11951 }
11952
11953 for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
11954 {
11955 SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
11956 }
11957 }
11958
11959 (*naddconss) += nconss;
11960
11961 /* for the statistic we count the number added variable constraints */
11962 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
11963
11964 SCIPfreeBufferArray(scip, &sinks);
11965 SCIPfreeBufferArray(scip, &sources);
11966
11967 return SCIP_OKAY;
11968}
11969
11970/** initialize the assumed durations for each variable */
11971static
11973 SCIP* scip, /**< SCIP data structure */
11974 TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
11975 SCIP_CONS** conss, /**< cumulative constraints */
11976 int nconss /**< number of cumulative constraints */
11977 )
11978{
11979 int c;
11980
11981 /* use the cumulative structure to define the duration we are using for each job */
11982 for( c = 0; c < nconss; ++c )
11983 {
11984 SCIP_CONSDATA* consdata;
11985 SCIP_VAR** vars;
11986 int nvars;
11987 int v;
11988
11989 consdata = SCIPconsGetData(conss[c]);
11990 assert(consdata != NULL);
11991
11992 vars = consdata->vars;
11993 nvars = consdata->nvars;
11994
11995 for( v = 0; v < nvars; ++v )
11996 {
11997 int idx;
11998
11999 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12000 assert(idx >= 0);
12001
12002 /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12003 * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12004 * general this is not the case. Therefore, the question would be which duration should be used?
12005 */
12006 tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12007 assert(tcliquegraph->durations[idx] > 0);
12008 }
12009 }
12010
12011 return SCIP_OKAY;
12012}
12013
12014/** create tclique graph */
12015static
12017 SCIP* scip, /**< SCIP data structure */
12018 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12019 )
12020{
12021 SCIP_VAR** vars;
12022 SCIP_HASHMAP* varmap;
12023 SCIP_Bool** precedencematrix;
12024 SCIP_Bool** demandmatrix;
12025 int* ninarcs;
12026 int* noutarcs;
12027 int* durations;
12028 int* weights;
12029 int nvars;
12030 int v;
12031
12034
12035 /* allocate memory for the tclique graph data structure */
12036 SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12037
12038 /* create the variable mapping hash map */
12040
12041 /* each active variables get a node in the graph */
12042 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12043
12044 /* allocate memory for the projected variables bound graph and the none overlapping graph */
12045 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12046 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12047
12048 /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12050 BMSclearMemoryArray(weights, nvars);
12051
12052 /* array to store the number of in arc of the precedence graph */
12054 BMSclearMemoryArray(ninarcs, nvars);
12055
12056 /* array to store the number of out arc of the precedence graph */
12057 SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12058 BMSclearMemoryArray(noutarcs, nvars);
12059
12060 /* array to store the used duration for each node */
12061 SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12062 BMSclearMemoryArray(durations, nvars);
12063
12064 for( v = 0; v < nvars; ++v )
12065 {
12066 SCIP_VAR* var;
12067
12068 var = vars[v];
12069 assert(var != NULL);
12070
12071 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12072 BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12073
12074 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12075 BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12076
12077 /* insert all active variables into the garph */
12079 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12080 }
12081
12082 (*tcliquegraph)->nnodes = nvars;
12083 (*tcliquegraph)->varmap = varmap;
12084 (*tcliquegraph)->precedencematrix = precedencematrix;
12085 (*tcliquegraph)->demandmatrix = demandmatrix;
12086 (*tcliquegraph)->weights = weights;
12087 (*tcliquegraph)->ninarcs = ninarcs;
12088 (*tcliquegraph)->noutarcs = noutarcs;
12089 (*tcliquegraph)->durations = durations;
12090 (*tcliquegraph)->size = nvars;
12091
12092 return SCIP_OKAY;
12093}
12094
12095/** frees the tclique graph */
12096static
12098 SCIP* scip, /**< SCIP data structure */
12099 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12100 )
12101{
12102 int v;
12103
12104 for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12105 {
12106 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12107 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12108 }
12109
12110 SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12111 SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12112 SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12113 SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12114 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12115 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12116 SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12117 SCIPhashmapFree(&(*tcliquegraph)->varmap);
12118
12119 SCIPfreeBuffer(scip, tcliquegraph);
12120}
12121
12122/** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12123 * constrains (disjunctive constraint)
12124 */
12125static
12127 SCIP* scip, /**< SCIP data structure */
12128 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12129 SCIP_CONS** conss, /**< array of cumulative constraints */
12130 int nconss, /**< number of cumulative constraints */
12131 int* naddconss /**< pointer to store the number of added constraints */
12132 )
12133{
12134 TCLIQUE_GRAPH* tcliquegraph;
12135
12136 /* create tclique graph */
12137 SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12138
12139 /* define for each job a duration */
12140 SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12141
12142 /* constuct incompatibility graph */
12143 SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12144
12145 /* search for new precedence constraints */
12146 if( conshdlrdata->detectvarbounds )
12147 {
12148 SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12149 }
12150
12151 /* search for new cumulative constraints */
12152 if( conshdlrdata->detectdisjunctive )
12153 {
12154 SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12155 }
12156
12157 /* free tclique graph data structure */
12158 freeTcliqueGraph(scip, &tcliquegraph);
12159
12160 return SCIP_OKAY;
12161}
12162
12163/** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12164static
12166 SCIP_CONSDATA* consdata /**< cumulative constraint data */
12167 )
12168{
12169 SCIP_VAR** vars;
12170 int nvars;
12171 int v;
12172
12173 if( consdata->validsignature )
12174 return;
12175
12176 vars = consdata->vars;
12177 nvars = consdata->nvars;
12178
12179 for( v = 0; v < nvars; ++v )
12180 {
12181 consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12182 }
12183
12184 consdata->validsignature = TRUE;
12185}
12186
12187/** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12188static
12190{ /*lint --e{715}*/
12191 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12192
12193 assert(consdata != NULL);
12194 assert(0 <= ind1 && ind1 < consdata->nvars);
12195 assert(0 <= ind2 && ind2 < consdata->nvars);
12196
12197 return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12198}
12199
12200/** run a pairwise comparison */
12201static
12203 SCIP* scip, /**< SCIP data structure */
12204 SCIP_CONS** conss, /**< array of cumulative constraints */
12205 int nconss, /**< number of cumulative constraints */
12206 int* ndelconss /**< pointer to store the number of deletedconstraints */
12207 )
12208{
12209 int i;
12210 int j;
12211
12212 for( i = 0; i < nconss; ++i )
12213 {
12214 SCIP_CONSDATA* consdata0;
12215 SCIP_CONS* cons0;
12216
12217 cons0 = conss[i];
12218 assert(cons0 != NULL);
12219
12220 consdata0 = SCIPconsGetData(cons0);
12221 assert(consdata0 != NULL);
12222
12223 consdataCalcSignature(consdata0);
12224 assert(consdata0->validsignature);
12225
12226 for( j = i+1; j < nconss; ++j )
12227 {
12228 SCIP_CONSDATA* consdata1;
12229 SCIP_CONS* cons1;
12230
12231 cons1 = conss[j];
12232 assert(cons1 != NULL);
12233
12234 consdata1 = SCIPconsGetData(cons1);
12235 assert(consdata1 != NULL);
12236
12237 if( consdata0->capacity != consdata1->capacity )
12238 continue;
12239
12240 consdataCalcSignature(consdata1);
12241 assert(consdata1->validsignature);
12242
12243 if( (consdata1->signature & (~consdata0->signature)) == 0 )
12244 {
12245 SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12246 SCIPswapPointers((void**)&cons0, (void**)&cons1);
12247 assert((consdata0->signature & (~consdata1->signature)) == 0);
12248 }
12249
12250 if( (consdata0->signature & (~consdata1->signature)) == 0 )
12251 {
12252 int* perm0;
12253 int* perm1;
12254 int v0;
12255 int v1;
12256
12257 if( consdata0->nvars > consdata1->nvars )
12258 continue;
12259
12260 if( consdata0->hmin < consdata1->hmin )
12261 continue;
12262
12263 if( consdata0->hmax > consdata1->hmax )
12264 continue;
12265
12266 SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12267 SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12268
12269 /* call sorting method */
12270 SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12271 SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12272
12273 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12274 {
12275 SCIP_VAR* var0;
12276 SCIP_VAR* var1;
12277 int idx0;
12278 int idx1;
12279 int comp;
12280
12281 idx0 = perm0[v0];
12282 idx1 = perm1[v1];
12283
12284 var0 = consdata0->vars[idx0];
12285
12286 var1 = consdata1->vars[idx1];
12287
12288 comp = SCIPvarCompare(var0, var1);
12289
12290 if( comp == 0 )
12291 {
12292 int duration0;
12293 int duration1;
12294 int demand0;
12295 int demand1;
12296
12297 demand0 = consdata0->demands[idx0];
12298 duration0 = consdata0->durations[idx0];
12299
12300 demand1 = consdata1->demands[idx1];
12301 duration1 = consdata1->durations[idx1];
12302
12303 if( demand0 != demand1 )
12304 break;
12305
12306 if( duration0 != duration1 )
12307 break;
12308
12309 v0++;
12310 v1++;
12311 }
12312 else if( comp > 0 )
12313 v1++;
12314 else
12315 break;
12316 }
12317
12318 if( v0 == consdata0->nvars )
12319 {
12320 if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12321 {
12322 initializeLocks(consdata1, TRUE);
12323 }
12324
12325 /* coverity[swapped_arguments] */
12326 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12327
12328 SCIP_CALL( SCIPdelCons(scip, cons0) );
12329 (*ndelconss)++;
12330 }
12331
12332 SCIPfreeBufferArray(scip, &perm1);
12333 SCIPfreeBufferArray(scip, &perm0);
12334 }
12335 }
12336 }
12337
12338 return SCIP_OKAY;
12339}
12340
12341/** strengthen the variable bounds using the cumulative condition */
12342static
12344 SCIP* scip, /**< SCIP data structure */
12345 SCIP_CONS* cons, /**< constraint to propagate */
12346 int* nchgbds, /**< pointer to store the number of changed bounds */
12347 int* naddconss /**< pointer to store the number of added constraints */
12348 )
12349{
12350 SCIP_CONSDATA* consdata;
12351 SCIP_VAR** vars;
12352 int* durations;
12353 int* demands;
12354 int capacity;
12355 int nvars;
12356 int nconss;
12357 int i;
12358
12359 consdata = SCIPconsGetData(cons);
12360 assert(consdata != NULL);
12361
12362 /* check if the variable bounds got already strengthen by the cumulative constraint */
12363 if( consdata->varbounds )
12364 return SCIP_OKAY;
12365
12366 vars = consdata->vars;
12367 durations = consdata->durations;
12368 demands = consdata->demands;
12369 capacity = consdata->capacity;
12370 nvars = consdata->nvars;
12371
12372 nconss = 0;
12373
12374 for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12375 {
12376 SCIP_VAR** vbdvars;
12377 SCIP_VAR* var;
12378 SCIP_Real* vbdcoefs;
12379 SCIP_Real* vbdconsts;
12380 int nvbdvars;
12381 int b;
12382 int j;
12383
12384 var = consdata->vars[i];
12385 assert(var != NULL);
12386
12387 vbdvars = SCIPvarGetVlbVars(var);
12388 vbdcoefs = SCIPvarGetVlbCoefs(var);
12389 vbdconsts = SCIPvarGetVlbConstants(var);
12390 nvbdvars = SCIPvarGetNVlbs(var);
12391
12392 for( b = 0; b < nvbdvars; ++b )
12393 {
12394 if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12395 {
12396 if( boundedConvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12397 {
12398 for( j = 0; j < nvars; ++j )
12399 {
12400 if( vars[j] == vbdvars[b] )
12401 break;
12402 }
12403 if( j == nvars )
12404 continue;
12405
12406 if( demands[i] + demands[j] > capacity &&
12407 boundedConvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12408 {
12409 SCIP_Bool infeasible;
12410 char name[SCIP_MAXSTRLEN];
12411 int nlocalbdchgs;
12412
12413 SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12414
12415 /* construct constraint name */
12416 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12417
12418 SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12419 nconss++;
12420
12421 SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12422 assert(!infeasible);
12423
12424 (*nchgbds) += nlocalbdchgs;
12425 }
12426 }
12427 }
12428 }
12429 }
12430
12431 (*naddconss) += nconss;
12432
12433 consdata->varbounds = TRUE;
12434
12435 return SCIP_OKAY;
12436}
12437
12438/** helper function to enforce constraints */
12439static
12441 SCIP* scip, /**< SCIP data structure */
12442 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12443 SCIP_CONS** conss, /**< constraints to process */
12444 int nconss, /**< number of constraints */
12445 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12446 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12447 SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12448 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12449 )
12450{
12451 SCIP_CONSHDLRDATA* conshdlrdata;
12452
12453 assert(conshdlr != NULL);
12454 assert(nconss == 0 || conss != NULL);
12455 assert(result != NULL);
12456
12458
12459 if( solinfeasible )
12460 {
12462 return SCIP_OKAY;
12463 }
12464
12465 SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12466 sol == NULL ? "LP" : "relaxation");
12467
12468 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12469 assert(conshdlrdata != NULL);
12470
12471 (*result) = SCIP_FEASIBLE;
12472
12473 if( conshdlrdata->usebinvars )
12474 {
12475 SCIP_Bool separated;
12477 int c;
12478
12479 separated = FALSE;
12480
12481 /* first check if a constraints is violated */
12482 for( c = 0; c < nusefulconss; ++c )
12483 {
12484 SCIP_CONS* cons;
12485 SCIP_Bool violated;
12486
12487 cons = conss[c];
12488 assert(cons != NULL);
12489
12490 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12491
12492 if( !violated )
12493 continue;
12494
12495 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12496 if ( cutoff )
12497 {
12499 return SCIP_OKAY;
12500 }
12501 }
12502
12503 for( ; c < nconss && !separated; ++c )
12504 {
12505 SCIP_CONS* cons;
12506 SCIP_Bool violated;
12507
12508 cons = conss[c];
12509 assert(cons != NULL);
12510
12511 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12512
12513 if( !violated )
12514 continue;
12515
12516 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12517 if ( cutoff )
12518 {
12520 return SCIP_OKAY;
12521 }
12522 }
12523
12524 if( separated )
12525 (*result) = SCIP_SEPARATED;
12526 }
12527 else
12528 {
12529 SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12530 }
12531
12532 return SCIP_OKAY;
12533}
12534
12535/**@} */
12536
12537
12538/**@name Callback methods of constraint handler
12539 *
12540 * @{
12541 */
12542
12543/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12544static
12545SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12546{ /*lint --e{715}*/
12547 assert(scip != NULL);
12548 assert(conshdlr != NULL);
12549
12551
12552 /* call inclusion method of constraint handler */
12554
12556
12557 *valid = TRUE;
12558
12559 return SCIP_OKAY;
12560}
12561
12562/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12563static
12564SCIP_DECL_CONSFREE(consFreeCumulative)
12565{ /*lint --e{715}*/
12566 SCIP_CONSHDLRDATA* conshdlrdata;
12567
12568 assert(conshdlr != NULL);
12569
12571
12572 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12573 assert(conshdlrdata != NULL);
12574
12575#ifdef SCIP_STATISTIC
12576 if( !conshdlrdata->iscopy )
12577 {
12578 /* statisitc output if SCIP_STATISTIC is defined */
12579 SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12580 conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12581 SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12582 conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12583 SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12584 conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12585 }
12586#endif
12587
12588 conshdlrdataFree(scip, &conshdlrdata);
12589
12590 SCIPconshdlrSetData(conshdlr, NULL);
12591
12592 return SCIP_OKAY;
12593}
12594
12595
12596/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12597static
12598SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12599{ /*lint --e{715}*/
12600 SCIP_CONSHDLRDATA* conshdlrdata;
12601 int c;
12602
12603 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12604 assert(conshdlrdata != NULL);
12605
12606 conshdlrdata->detectedredundant = FALSE;
12607
12608 for( c = 0; c < nconss; ++c )
12609 {
12610 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12611 * hmax)
12612 */
12614 }
12615
12616 return SCIP_OKAY;
12617}
12618
12619
12620/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12621#ifdef SCIP_STATISTIC
12622static
12623SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12624{ /*lint --e{715}*/
12625 SCIP_CONSHDLRDATA* conshdlrdata;
12626 int c;
12627
12628 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12629 assert(conshdlrdata != NULL);
12630
12631 for( c = 0; c < nconss; ++c )
12632 {
12633 SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12634
12635#ifdef SCIP_DISABLED_CODE
12637#endif
12638 }
12639
12640 if( !conshdlrdata->iscopy )
12641 {
12642 SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12643 SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12644 SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12645 SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12646 SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12647 SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12648 SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12649 SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12650 SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12651 }
12652
12653 return SCIP_OKAY;
12654}
12655#endif
12656
12657
12658/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12659static
12660SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12661{ /*lint --e{715}*/
12662 SCIP_CONSDATA* consdata;
12663 int c;
12664
12665 assert(conshdlr != NULL);
12666
12668
12669 /* release the rows of all constraints */
12670 for( c = 0; c < nconss; ++c )
12671 {
12672 consdata = SCIPconsGetData(conss[c]);
12673 assert(consdata != NULL);
12674
12675 /* free rows */
12676 SCIP_CALL( consdataFreeRows(scip, &consdata) );
12677 }
12678
12679 return SCIP_OKAY;
12680}
12681
12682/** frees specific constraint data */
12683static
12684SCIP_DECL_CONSDELETE(consDeleteCumulative)
12685{ /*lint --e{715}*/
12686 assert(conshdlr != NULL);
12687 assert(consdata != NULL );
12688 assert(*consdata != NULL );
12689
12691
12692 /* if constraint belongs to transformed problem space, drop bound change events on variables */
12693 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12694 {
12695 SCIP_CONSHDLRDATA* conshdlrdata;
12696
12697 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12698 assert(conshdlrdata != NULL);
12699
12700 SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12701 }
12702
12703 /* free cumulative constraint data */
12704 SCIP_CALL( consdataFree(scip, consdata) );
12705
12706 return SCIP_OKAY;
12707}
12708
12709/** transforms constraint data into data belonging to the transformed problem */
12710static
12711SCIP_DECL_CONSTRANS(consTransCumulative)
12712{ /*lint --e{715}*/
12713 SCIP_CONSHDLRDATA* conshdlrdata;
12714 SCIP_CONSDATA* sourcedata;
12715 SCIP_CONSDATA* targetdata;
12716
12717 assert(conshdlr != NULL);
12719 assert(sourcecons != NULL);
12720 assert(targetcons != NULL);
12721
12722 sourcedata = SCIPconsGetData(sourcecons);
12723 assert(sourcedata != NULL);
12724 assert(sourcedata->demandrows == NULL);
12725
12726 SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12727
12728 /* get event handler */
12729 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12730 assert(conshdlrdata != NULL);
12731 assert(conshdlrdata->eventhdlr != NULL);
12732
12733 /* create constraint data for target constraint */
12734 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12735 sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12736 sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12737
12738 /* create target constraint */
12739 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12740 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12741 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12742 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12743 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12744
12745 /* catch bound change events of variables */
12746 SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12747
12748 return SCIP_OKAY;
12749}
12750
12751/** LP initialization method of constraint handler */
12752static
12753SCIP_DECL_CONSINITLP(consInitlpCumulative)
12754{
12755 SCIP_CONSHDLRDATA* conshdlrdata;
12756 int c;
12757
12758 assert(conshdlr != NULL);
12759
12761
12762 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12763 assert(conshdlrdata != NULL);
12764
12765 *infeasible = FALSE;
12766
12767 SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12768
12769 if( conshdlrdata->usebinvars )
12770 {
12771 /* add rows to LP */
12772 for( c = 0; c < nconss && !(*infeasible); ++c )
12773 {
12774 assert(SCIPconsIsInitial(conss[c]));
12775 SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12776
12777 if( conshdlrdata->cutsasconss )
12778 {
12780 }
12781 }
12782 }
12783
12784 /**@todo if we want to use only the integer variables; only these will be in cuts
12785 * create some initial cuts, currently these are only separated */
12786
12787 return SCIP_OKAY;
12788}
12789
12790/** separation method of constraint handler for LP solutions */
12791static
12792SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12793{
12794 SCIP_CONSHDLRDATA* conshdlrdata;
12796 SCIP_Bool separated;
12797 int c;
12798
12799 SCIPdebugMsg(scip, "consSepalpCumulative\n");
12800
12801 assert(conshdlr != NULL);
12802 assert(nconss == 0 || conss != NULL);
12803 assert(result != NULL);
12804
12806
12807 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12808 assert(conshdlrdata != NULL);
12809
12810 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12811
12812 cutoff = FALSE;
12813 separated = FALSE;
12814 (*result) = SCIP_DIDNOTRUN;
12815
12816 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12817 return SCIP_OKAY;
12818
12819 (*result) = SCIP_DIDNOTFIND;
12820
12821 if( conshdlrdata->usebinvars )
12822 {
12823 /* check all useful cumulative constraints for feasibility */
12824 for( c = 0; c < nusefulconss && !cutoff; ++c )
12825 {
12826 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12827 }
12828
12829 if( !cutoff && conshdlrdata->usecovercuts )
12830 {
12831 for( c = 0; c < nusefulconss; ++c )
12832 {
12833 SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12834 }
12835 }
12836 }
12837
12838 if( conshdlrdata->sepaold )
12839 {
12840 /* separate cuts containing only integer variables */
12841 for( c = 0; c < nusefulconss; ++c )
12842 {
12843 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12844 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12845 }
12846 }
12847
12848 if( cutoff )
12850 else if( separated )
12852
12853 return SCIP_OKAY;
12854}
12855
12856/** separation method of constraint handler for arbitrary primal solutions */
12857static
12858SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12859{ /*lint --e{715}*/
12860 SCIP_CONSHDLRDATA* conshdlrdata;
12862 SCIP_Bool separated;
12863 int c;
12864
12865 assert(conshdlr != NULL);
12866 assert(nconss == 0 || conss != NULL);
12867 assert(result != NULL);
12868
12870
12871 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12872 assert(conshdlrdata != NULL);
12873
12874 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12875 return SCIP_OKAY;
12876
12877 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12878
12879 cutoff = FALSE;
12880 separated = FALSE;
12881 (*result) = SCIP_DIDNOTFIND;
12882
12883 if( conshdlrdata->usebinvars )
12884 {
12885 /* check all useful cumulative constraints for feasibility */
12886 for( c = 0; c < nusefulconss && !cutoff; ++c )
12887 {
12888 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12889 }
12890
12891 if( !cutoff && conshdlrdata->usecovercuts )
12892 {
12893 for( c = 0; c < nusefulconss; ++c )
12894 {
12895 SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12896 }
12897 }
12898 }
12899 if( conshdlrdata->sepaold )
12900 {
12901 /* separate cuts containing only integer variables */
12902 for( c = 0; c < nusefulconss; ++c )
12903 {
12904 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12905 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12906 }
12907 }
12908
12909 if( cutoff )
12911 else if( separated )
12913
12914 return SCIP_OKAY;
12915}
12916
12917/** constraint enforcing method of constraint handler for LP solutions */
12918static
12919SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12920{ /*lint --e{715}*/
12921 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12922
12923 return SCIP_OKAY;
12924}
12925
12926/** constraint enforcing method of constraint handler for relaxation solutions */
12927static
12928SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
12929{ /*lint --e{715}*/
12930 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12931
12932 return SCIP_OKAY;
12933}
12934
12935/** constraint enforcing method of constraint handler for pseudo solutions */
12936static
12937SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12938{ /*lint --e{715}*/
12939 SCIP_CONSHDLRDATA* conshdlrdata;
12940
12941 SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
12942
12943 assert(conshdlr != NULL);
12944 assert(nconss == 0 || conss != NULL);
12945 assert(result != NULL);
12946
12948
12949 if( objinfeasible )
12950 {
12952 return SCIP_OKAY;
12953 }
12954
12955 (*result) = SCIP_FEASIBLE;
12956
12957 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12958 assert(conshdlrdata != NULL);
12959
12960 SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
12961
12962 return SCIP_OKAY;
12963}
12964
12965/** feasibility check method of constraint handler for integral solutions */
12966static
12967SCIP_DECL_CONSCHECK(consCheckCumulative)
12968{ /*lint --e{715}*/
12969 int c;
12970
12971 assert(conshdlr != NULL);
12972 assert(nconss == 0 || conss != NULL);
12973 assert(result != NULL);
12974
12976
12978
12979 SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
12980
12981 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
12982 {
12983 SCIP_Bool violated = FALSE;
12984
12985 SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
12986
12987 if( violated )
12989 }
12990
12991 return SCIP_OKAY;
12992}
12993
12994/** domain propagation method of constraint handler */
12995static
12996SCIP_DECL_CONSPROP(consPropCumulative)
12997{ /*lint --e{715}*/
12998 SCIP_CONSHDLRDATA* conshdlrdata;
13000 int nchgbds;
13001 int ndelconss;
13002 int c;
13003
13004 SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13005
13006 assert(conshdlr != NULL);
13007 assert(nconss == 0 || conss != NULL);
13008 assert(result != NULL);
13009
13011
13012 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13013 assert(conshdlrdata != NULL);
13014
13015 nchgbds = 0;
13016 ndelconss = 0;
13017 cutoff = FALSE;
13018 (*result) = SCIP_DIDNOTRUN;
13019
13020 /* propgate all useful constraints */
13021 for( c = 0; c < nusefulconss && !cutoff; ++c )
13022 {
13023 SCIP_CONS* cons;
13024
13025 cons = conss[c];
13026 assert(cons != NULL);
13027
13028 if( SCIPgetDepth(scip) == 0 )
13029 {
13031 &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13032
13033 if( cutoff )
13034 break;
13035
13036 if( SCIPconsIsDeleted(cons) )
13037 continue;
13038 }
13039
13040 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13041 }
13042
13043 if( !cutoff && nchgbds == 0 )
13044 {
13045 /* propgate all other constraints */
13046 for( c = nusefulconss; c < nconss && !cutoff; ++c )
13047 {
13048 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13049 }
13050 }
13051
13052 if( cutoff )
13053 {
13054 SCIPdebugMsg(scip, "detected infeasible\n");
13056 }
13057 else if( nchgbds > 0 )
13058 {
13059 SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13061 }
13062 else
13064
13065 return SCIP_OKAY;
13066}
13067
13068/** presolving method of constraint handler */
13069static
13070SCIP_DECL_CONSPRESOL(consPresolCumulative)
13071{ /*lint --e{715}*/
13072 SCIP_CONSHDLRDATA* conshdlrdata;
13073 SCIP_CONS* cons;
13075 SCIP_Bool unbounded;
13076 int oldnfixedvars;
13077 int oldnchgbds;
13078 int oldndelconss;
13079 int oldnaddconss;
13080 int oldnupgdconss;
13081 int oldnchgsides;
13082 int oldnchgcoefs;
13083 int c;
13084
13085 assert(conshdlr != NULL);
13086 assert(scip != NULL);
13087 assert(result != NULL);
13088
13090
13091 SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13092
13093 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13094 assert(conshdlrdata != NULL);
13095
13097
13098 oldnfixedvars = *nfixedvars;
13099 oldnchgbds = *nchgbds;
13100 oldnchgsides = *nchgsides;
13101 oldnchgcoefs = *nchgcoefs;
13102 oldnupgdconss = *nupgdconss;
13103 oldndelconss = *ndelconss;
13104 oldnaddconss = *naddconss;
13105 cutoff = FALSE;
13106 unbounded = FALSE;
13107
13108 /* process constraints */
13109 for( c = 0; c < nconss && !cutoff; ++c )
13110 {
13111 cons = conss[c];
13112
13113 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13114 * hmax)
13115 */
13117
13118 if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13119 {
13120 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13121 nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13122
13123 if( cutoff || unbounded )
13124 break;
13125
13126 if( SCIPconsIsDeleted(cons) )
13127 continue;
13128 }
13129
13130 /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13131 if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13132 {
13133 SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13134 }
13135
13136 /* strengthen existing variable bounds using the cumulative condition */
13137 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13138 {
13139 SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13140 }
13141
13142 /* propagate cumulative constraint */
13143 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13144 assert(checkDemands(scip, cons) || cutoff);
13145 }
13146
13147 if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13148 {
13149 SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13150 }
13151
13152 /* only perform the detection of variable bounds and disjunctive constraint once */
13153 if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13154 && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13155 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13156 {
13157 /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13158 * propagation
13159 */
13160 SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13161 conshdlrdata->detectedredundant = TRUE;
13162 }
13163
13164 if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13165 {
13166 SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13167 }
13168
13169 SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13170 *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13171
13172 if( cutoff )
13174 else if( unbounded )
13176 else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13177 || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13179 else
13181
13182 return SCIP_OKAY;
13183}
13184
13185/** propagation conflict resolving method of constraint handler */
13186static
13187SCIP_DECL_CONSRESPROP(consRespropCumulative)
13188{ /*lint --e{715}*/
13189 SCIP_CONSHDLRDATA* conshdlrdata;
13190 SCIP_CONSDATA* consdata;
13191
13192 assert(conshdlr != NULL);
13193 assert(scip != NULL);
13194 assert(result != NULL);
13195 assert(infervar != NULL);
13196 assert(bdchgidx != NULL);
13197
13199
13200 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13201 assert(conshdlrdata != NULL);
13202
13203 /* process constraint */
13204 assert(cons != NULL);
13205
13206 consdata = SCIPconsGetData(cons);
13207 assert(consdata != NULL);
13208
13209 SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13210 SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13212
13213 SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13214 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13215 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13216
13217 return SCIP_OKAY;
13218}
13219
13220/** variable rounding lock method of constraint handler */
13221static
13222SCIP_DECL_CONSLOCK(consLockCumulative)
13223{ /*lint --e{715}*/
13224 SCIP_CONSDATA* consdata;
13225 SCIP_VAR** vars;
13226 int v;
13227
13228 SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13229
13230 assert(scip != NULL);
13231 assert(cons != NULL);
13232 assert(locktype == SCIP_LOCKTYPE_MODEL);
13233
13234 consdata = SCIPconsGetData(cons);
13235 assert(consdata != NULL);
13236
13237 vars = consdata->vars;
13238 assert(vars != NULL);
13239
13240 for( v = 0; v < consdata->nvars; ++v )
13241 {
13242 if( consdata->downlocks[v] && consdata->uplocks[v] )
13243 {
13244 /* the integer start variable should not get rounded in both direction */
13245 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13246 }
13247 else if( consdata->downlocks[v] )
13248 {
13249 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13250 }
13251 else if( consdata->uplocks[v] )
13252 {
13253 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13254 }
13255 }
13256
13257 return SCIP_OKAY;
13258}
13259
13260
13261/** constraint display method of constraint handler */
13262static
13263SCIP_DECL_CONSPRINT(consPrintCumulative)
13264{ /*lint --e{715}*/
13265 assert(scip != NULL);
13266 assert(conshdlr != NULL);
13267 assert(cons != NULL);
13268
13269 consdataPrint(scip, SCIPconsGetData(cons), file);
13270
13271 return SCIP_OKAY;
13272}
13273
13274/** constraint copying method of constraint handler */
13275static
13276SCIP_DECL_CONSCOPY(consCopyCumulative)
13277{ /*lint --e{715}*/
13278 SCIP_CONSDATA* sourceconsdata;
13279 SCIP_VAR** sourcevars;
13280 SCIP_VAR** vars;
13281 const char* consname;
13282
13283 int nvars;
13284 int v;
13285
13286 sourceconsdata = SCIPconsGetData(sourcecons);
13287 assert(sourceconsdata != NULL);
13288
13289 /* get variables of the source constraint */
13290 nvars = sourceconsdata->nvars;
13291 sourcevars = sourceconsdata->vars;
13292
13293 (*valid) = TRUE;
13294
13295 if( nvars == 0 )
13296 return SCIP_OKAY;
13297
13298 /* allocate buffer array */
13300
13301 for( v = 0; v < nvars && *valid; ++v )
13302 {
13303 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13304 assert(!(*valid) || vars[v] != NULL);
13305 }
13306
13307 /* only create the target constraint, if all variables could be copied */
13308 if( *valid )
13309 {
13310 if( name != NULL )
13311 consname = name;
13312 else
13313 consname = SCIPconsGetName(sourcecons);
13314
13315 /* create a copy of the cumulative constraint */
13317 sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13318 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13319
13320 /* adjust left side if the time axis if needed */
13321 if( sourceconsdata->hmin > 0 )
13322 {
13323 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13324 }
13325
13326 /* adjust right side if the time axis if needed */
13327 if( sourceconsdata->hmax < INT_MAX )
13328 {
13329 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13330 }
13331 }
13332
13333 /* free buffer array */
13335
13336 return SCIP_OKAY;
13337}
13338
13339
13340/** constraint parsing method of constraint handler */
13341static
13342SCIP_DECL_CONSPARSE(consParseCumulative)
13343{ /*lint --e{715}*/
13344 SCIP_VAR** vars;
13345 SCIP_VAR* var;
13346 SCIP_Real value;
13347 char strvalue[SCIP_MAXSTRLEN];
13348 char* endptr;
13349 int* demands;
13350 int* durations;
13351 int capacity;
13352 int duration;
13353 int demand;
13354 int hmin;
13355 int hmax;
13356 int varssize;
13357 int nvars;
13358
13359 SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13360
13361 *success = TRUE;
13362
13363 /* cutoff "cumulative" form the constraint string */
13364 SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13365 str = endptr;
13366
13367 varssize = 100;
13368 nvars = 0;
13369
13370 /* allocate buffer array for variables */
13371 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13372 SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13373 SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13374
13375 do
13376 {
13377 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13378
13379 if( var == NULL )
13380 {
13381 endptr = strchr(endptr, ')');
13382
13383 if( endptr == NULL )
13384 *success = FALSE;
13385 else
13386 str = endptr;
13387
13388 break;
13389 }
13390
13391 str = endptr;
13392 SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13393 duration = atoi(strvalue);
13394 str = endptr;
13395
13396 SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13397 demand = atoi(strvalue);
13398 str = endptr;
13399
13400 SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13401
13402 vars[nvars] = var;
13403 demands[nvars] = demand;
13404 durations[nvars] = duration;
13405 nvars++;
13406 }
13407 while( *str != ')' );
13408
13409 if( *success )
13410 {
13411 /* parse effective time window */
13412 SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13413 hmin = atoi(strvalue);
13414 str = endptr;
13415
13416 if( SCIPparseReal(scip, str, &value, &endptr) )
13417 {
13418 hmax = boundedConvertRealToInt(scip, value);
13419 str = endptr;
13420
13421 /* parse capacity */
13422 SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13423 str = endptr;
13424 if( SCIPparseReal(scip, str, &value, &endptr) )
13425 {
13426 capacity = (int)value;
13427
13428 /* create cumulative constraint */
13429 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13430 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13431
13432 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13433 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13434 }
13435 }
13436 }
13437
13438 /* free buffer arrays */
13439 SCIPfreeBufferArray(scip, &durations);
13440 SCIPfreeBufferArray(scip, &demands);
13442
13443 return SCIP_OKAY;
13444}
13445
13446
13447/** constraint method of constraint handler which returns the variables (if possible) */
13448static
13449SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13450{ /*lint --e{715}*/
13451 SCIP_CONSDATA* consdata;
13452
13453 consdata = SCIPconsGetData(cons);
13454 assert(consdata != NULL);
13455
13456 if( varssize < consdata->nvars )
13457 (*success) = FALSE;
13458 else
13459 {
13460 assert(vars != NULL);
13461
13462 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13463 (*success) = TRUE;
13464 }
13465
13466 return SCIP_OKAY;
13467}
13468
13469/** constraint method of constraint handler which returns the number of variables (if possible) */
13470static
13471SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13472{ /*lint --e{715}*/
13473 SCIP_CONSDATA* consdata;
13474
13475 consdata = SCIPconsGetData(cons);
13476 assert(consdata != NULL);
13477
13478 (*nvars) = consdata->nvars;
13479 (*success) = TRUE;
13480
13481 return SCIP_OKAY;
13482}
13483
13484/**@} */
13485
13486/**@name Callback methods of event handler
13487 *
13488 * @{
13489 */
13490
13491
13492/** execution method of event handler */
13493static
13494SCIP_DECL_EVENTEXEC(eventExecCumulative)
13495{ /*lint --e{715}*/
13496 SCIP_CONSDATA* consdata;
13497
13498 assert(scip != NULL);
13499 assert(eventhdlr != NULL);
13500 assert(eventdata != NULL);
13501 assert(event != NULL);
13502
13504
13505 consdata = (SCIP_CONSDATA*)eventdata;
13506 assert(consdata != NULL);
13507
13508 /* mark the constraint to be not propagated */
13509 consdata->propagated = FALSE;
13510
13511 return SCIP_OKAY;
13512}
13513
13514/**@} */
13515
13516/*
13517 * constraint specific interface methods
13518 */
13519
13520/** creates the handler for cumulative constraints and includes it in SCIP */
13522 SCIP* scip /**< SCIP data structure */
13523 )
13524{
13525 SCIP_CONSHDLRDATA* conshdlrdata;
13526 SCIP_CONSHDLR* conshdlr;
13527 SCIP_EVENTHDLR* eventhdlr;
13528
13529 /* create event handler for bound change events */
13530 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13531
13532 /* create cumulative constraint handler data */
13533 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13534
13535 /* include constraint handler */
13538 consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13539 conshdlrdata) );
13540
13541 assert(conshdlr != NULL);
13542
13543 /* set non-fundamental callbacks via specific setter functions */
13544 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13545 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13546#ifdef SCIP_STATISTIC
13547 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13548#endif
13549 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13550 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13551 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13552 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13553 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13554 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13555 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13556 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13558 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13561 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13562 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13564 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13565 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13566
13567 /* add cumulative constraint handler parameters */
13569 "constraints/" CONSHDLR_NAME "/maxtime", "maximum range for time horizon",
13570 &conshdlrdata->maxtime, TRUE, DEFAULT_MAXTIME, 0, INT_MAX, NULL, NULL) );
13572 "constraints/" CONSHDLR_NAME "/ttinfer",
13573 "should time-table (core-times) propagator be used to infer bounds?",
13574 &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13576 "constraints/" CONSHDLR_NAME "/efcheck",
13577 "should edge-finding be used to detect an overload?",
13578 &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13580 "constraints/" CONSHDLR_NAME "/efinfer",
13581 "should edge-finding be used to infer bounds?",
13582 &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13584 "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13585 &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13587 "constraints/" CONSHDLR_NAME "/ttefcheck",
13588 "should time-table edge-finding be used to detect an overload?",
13589 &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13591 "constraints/" CONSHDLR_NAME "/ttefinfer",
13592 "should time-table edge-finding be used to infer bounds?",
13593 &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13594
13596 "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13597 &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13599 "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13600 &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13602 "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13603 &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13605 "constraints/" CONSHDLR_NAME "/cutsasconss",
13606 "should the cumulative constraint create cuts as knapsack constraints?",
13607 &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13609 "constraints/" CONSHDLR_NAME "/sepaold",
13610 "shall old sepa algo be applied?",
13611 &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13612
13614 "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13615 &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13616
13617 /* presolving parameters */
13619 "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13620 &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13622 "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13623 &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13625 "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13626 &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13628 "constraints/" CONSHDLR_NAME "/presolpairwise",
13629 "should pairwise constraint comparison be performed in presolving?",
13630 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13632 "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13633 &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13634
13636 "constraints/" CONSHDLR_NAME "/maxnodes",
13637 "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13638 &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13640 "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13641 &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13643 "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13644 &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13645
13646 /* conflict analysis parameters */
13648 "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13649 &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13650
13651 return SCIP_OKAY;
13652}
13653
13654/** creates and captures a cumulative constraint */
13656 SCIP* scip, /**< SCIP data structure */
13657 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13658 const char* name, /**< name of constraint */
13659 int nvars, /**< number of variables (jobs) */
13660 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13661 int* durations, /**< array containing corresponding durations */
13662 int* demands, /**< array containing corresponding demands */
13663 int capacity, /**< available cumulative capacity */
13664 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13665 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13666 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13667 * Usually set to TRUE. */
13668 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13669 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13670 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13671 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13672 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13673 * Usually set to TRUE. */
13674 SCIP_Bool local, /**< is constraint only valid locally?
13675 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13676 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13677 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13678 * adds coefficients to this constraint. */
13679 SCIP_Bool dynamic, /**< is constraint subject to aging?
13680 * Usually set to FALSE. Set to TRUE for own cuts which
13681 * are seperated as constraints. */
13682 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13683 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13684 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13685 * if it may be moved to a more global node?
13686 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13687 )
13688{
13689 int i;
13690 SCIP_CONSHDLR* conshdlr;
13691 SCIP_CONSDATA* consdata;
13692
13693 assert(scip != NULL);
13694
13695 /* find the cumulative constraint handler */
13696 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13697 if( conshdlr == NULL )
13698 {
13699 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13700 return SCIP_PLUGINNOTFOUND;
13701 }
13702
13703 for( i = 0; i < nvars; ++i )
13704 {
13705 if( INT_MAX - durations[i] < boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(vars[i])) )
13706 {
13707 SCIPerrorMessage("detected potential integer overflow for variable <%s> in constraint <%s>: "
13708 "decrease upper bound of variable or time horizon constraints/" CONSHDLR_NAME "/maxtime\n",
13709 name, SCIPvarGetName(vars[i]));
13710 return SCIP_INVALIDDATA;
13711 }
13712 }
13713 SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13714
13715 /* create constraint data */
13716 SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13717
13718 /* create constraint */
13719 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13720 initial, separate, enforce, check, propagate,
13721 local, modifiable, dynamic, removable, stickingatnode) );
13722
13724 {
13725 SCIP_CONSHDLRDATA* conshdlrdata;
13726
13727 /* get event handler */
13728 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13729 assert(conshdlrdata != NULL);
13730 assert(conshdlrdata->eventhdlr != NULL);
13731
13732 /* catch bound change events of variables */
13733 SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13734 }
13735
13736 return SCIP_OKAY;
13737}
13738
13739/** creates and captures a cumulative constraint
13740 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13741 * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13742 *
13743 * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13744 *
13745 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13746 */
13748 SCIP* scip, /**< SCIP data structure */
13749 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13750 const char* name, /**< name of constraint */
13751 int nvars, /**< number of variables (jobs) */
13752 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13753 int* durations, /**< array containing corresponding durations */
13754 int* demands, /**< array containing corresponding demands */
13755 int capacity /**< available cumulative capacity */
13756 )
13757{
13758 assert(scip != NULL);
13759
13760 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13762
13763 return SCIP_OKAY;
13764}
13765
13766/** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13768 SCIP* scip, /**< SCIP data structure */
13769 SCIP_CONS* cons, /**< constraint data */
13770 int hmin /**< left bound of time axis to be considered */
13771 )
13772{
13773 SCIP_CONSDATA* consdata;
13774
13776
13777 consdata = SCIPconsGetData(cons);
13778 assert(consdata != NULL);
13779
13780 if( hmin < 0 || hmin > consdata->hmax )
13781 {
13782 SCIPerrorMessage("invalid value of hmin for cumulative constraint <%s>\n",
13783 SCIPconsGetName(cons));
13784 return SCIP_INVALIDCALL;
13785 }
13786
13787 consdata->hmin = hmin;
13788
13789 return SCIP_OKAY;
13790}
13791
13792/** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13794 SCIP* scip, /**< SCIP data structure */
13795 SCIP_CONS* cons /**< constraint */
13796 )
13797{
13798 SCIP_CONSDATA* consdata;
13799
13801
13802 consdata = SCIPconsGetData(cons);
13803 assert(consdata != NULL);
13804
13805 return consdata->hmin;
13806}
13807
13808/** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13810 SCIP* scip, /**< SCIP data structure */
13811 SCIP_CONS* cons, /**< constraint data */
13812 int hmax /**< right bound of time axis to be considered */
13813 )
13814{
13815 SCIP_CONSDATA* consdata;
13816
13818
13819 consdata = SCIPconsGetData(cons);
13820 assert(consdata != NULL);
13821
13822 if( hmax < consdata->hmin )
13823 {
13824 SCIPerrorMessage("invalid value of hmax for cumulative constraint <%s>\n",
13825 SCIPconsGetName(cons));
13826 return SCIP_INVALIDCALL;
13827 }
13828
13829 consdata->hmax = hmax;
13830
13831 return SCIP_OKAY;
13832}
13833
13834/** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13836 SCIP* scip, /**< SCIP data structure */
13837 SCIP_CONS* cons /**< constraint */
13838 )
13839{
13840 SCIP_CONSDATA* consdata;
13841
13843
13844 consdata = SCIPconsGetData(cons);
13845 assert(consdata != NULL);
13846
13847 return consdata->hmax;
13848}
13849
13850/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13852 SCIP* scip, /**< SCIP data structure */
13853 SCIP_CONS* cons /**< constraint data */
13854 )
13855{
13856 SCIP_CONSDATA* consdata;
13857
13859
13860 consdata = SCIPconsGetData(cons);
13861 assert(consdata != NULL);
13862
13863 return consdata->vars;
13864}
13865
13866/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13868 SCIP* scip, /**< SCIP data structure */
13869 SCIP_CONS* cons /**< constraint data */
13870 )
13871{
13872 SCIP_CONSDATA* consdata;
13873
13875
13876 consdata = SCIPconsGetData(cons);
13877 assert(consdata != NULL);
13878
13879 return consdata->nvars;
13880}
13881
13882/** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13884 SCIP* scip, /**< SCIP data structure */
13885 SCIP_CONS* cons /**< constraint data */
13886 )
13887{
13888 SCIP_CONSDATA* consdata;
13889
13891
13892 consdata = SCIPconsGetData(cons);
13893 assert(consdata != NULL);
13894
13895 return consdata->capacity;
13896}
13897
13898/** returns the durations of the cumulative constraint */ /*lint -e{715}*/
13900 SCIP* scip, /**< SCIP data structure */
13901 SCIP_CONS* cons /**< constraint data */
13902 )
13903{
13904 SCIP_CONSDATA* consdata;
13905
13907
13908 consdata = SCIPconsGetData(cons);
13909 assert(consdata != NULL);
13910
13911 return consdata->durations;
13912}
13913
13914/** returns the demands of the cumulative constraint */ /*lint -e{715}*/
13916 SCIP* scip, /**< SCIP data structure */
13917 SCIP_CONS* cons /**< constraint data */
13918 )
13919{
13920 SCIP_CONSDATA* consdata;
13921
13923
13924 consdata = SCIPconsGetData(cons);
13925 assert(consdata != NULL);
13926
13927 return consdata->demands;
13928}
13929
13930/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
13931 * given solution is satisfied
13932 */
13934 SCIP* scip, /**< SCIP data structure */
13935 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
13936 int nvars, /**< number of variables (jobs) */
13937 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13938 int* durations, /**< array containing corresponding durations */
13939 int* demands, /**< array containing corresponding demands */
13940 int capacity, /**< available cumulative capacity */
13941 int hmin, /**< left bound of time axis to be considered (including hmin) */
13942 int hmax, /**< right bound of time axis to be considered (not including hmax) */
13943 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
13944 SCIP_CONS* cons, /**< constraint which is checked */
13945 SCIP_Bool printreason /**< should the reason for the violation be printed? */
13946 )
13947{
13948 assert(scip != NULL);
13949 assert(violated != NULL);
13950
13951 SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
13952 violated, cons, printreason) );
13953
13954 return SCIP_OKAY;
13955}
13956
13957/** normalize cumulative condition */ /*lint -e{715}*/
13959 SCIP* scip, /**< SCIP data structure */
13960 int nvars, /**< number of start time variables (activities) */
13961 SCIP_VAR** vars, /**< array of start time variables */
13962 int* durations, /**< array of durations */
13963 int* demands, /**< array of demands */
13964 int* capacity, /**< pointer to store the changed cumulative capacity */
13965 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
13966 int* nchgsides /**< pointer to count number of side changes */
13967 )
13968{ /*lint --e{715}*/
13969 normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
13970
13971 return SCIP_OKAY;
13972}
13973
13974/** searches for a time point within the cumulative condition were the cumulative condition can be split */
13976 SCIP* scip, /**< SCIP data structure */
13977 int nvars, /**< number of variables (jobs) */
13978 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13979 int* durations, /**< array containing corresponding durations */
13980 int* demands, /**< array containing corresponding demands */
13981 int capacity, /**< available cumulative capacity */
13982 int* hmin, /**< pointer to store the left bound of the effective horizon */
13983 int* hmax, /**< pointer to store the right bound of the effective horizon */
13984 int* split /**< point were the cumulative condition can be split */
13985 )
13986{
13987 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
13988 hmin, hmax, split) );
13989
13990 return SCIP_OKAY;
13991}
13992
13993/** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
13995 SCIP* scip, /**< SCIP data structure */
13996 int nvars, /**< number of start time variables (activities) */
13997 SCIP_VAR** vars, /**< array of start time variables */
13998 int* durations, /**< array of durations */
13999 int hmin, /**< left bound of time axis to be considered */
14000 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14001 SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14002 SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14003 SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14004 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14005 int* nfixedvars, /**< pointer to store the number of fixed variables */
14006 int* nchgsides, /**< pointer to store the number of changed sides */
14007 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14008 )
14009{
14010 if( nvars <= 1 )
14011 return SCIP_OKAY;
14012
14013 /* presolve constraint form the earlier start time point of view */
14014 SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14015 irrelevants, nfixedvars, nchgsides, cutoff) );
14016
14017 /* presolve constraint form the latest completion time point of view */
14018 SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14019 irrelevants, nfixedvars, nchgsides, cutoff) );
14020
14021 return SCIP_OKAY;
14022}
14023
14024/** propagate the given cumulative condition */
14026 SCIP* scip, /**< SCIP data structure */
14027 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14028 int nvars, /**< number of variables (jobs) */
14029 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14030 int* durations, /**< array containing corresponding durations */
14031 int* demands, /**< array containing corresponding demands */
14032 int capacity, /**< available cumulative capacity */
14033 int hmin, /**< left bound of time axis to be considered (including hmin) */
14034 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14035 SCIP_CONS* cons, /**< constraint which gets propagated */
14036 int* nchgbds, /**< pointer to store the number of variable bound changes */
14037 SCIP_Bool* initialized, /**< was conflict analysis initialized */
14038 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14039 SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14040 )
14041{
14042 SCIP_CONSHDLR* conshdlr;
14043 SCIP_CONSHDLRDATA* conshdlrdata;
14044 SCIP_Bool redundant;
14045
14046 assert(scip != NULL);
14047 assert(cons != NULL);
14048 assert(initialized != NULL);
14049 assert(*initialized == FALSE);
14050 assert(cutoff != NULL);
14051 assert(*cutoff == FALSE);
14052
14053 /* find the cumulative constraint handler */
14054 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14055 if( conshdlr == NULL )
14056 {
14057 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14058 return SCIP_PLUGINNOTFOUND;
14059 }
14060
14061 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14062 assert(conshdlrdata != NULL);
14063
14064 redundant = FALSE;
14065
14066 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14067 nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14068 nchgbds, &redundant, initialized, explanation, cutoff) );
14069
14070 return SCIP_OKAY;
14071}
14072
14073/** resolve propagation w.r.t. the cumulative condition */
14075 SCIP* scip, /**< SCIP data structure */
14076 int nvars, /**< number of start time variables (activities) */
14077 SCIP_VAR** vars, /**< array of start time variables */
14078 int* durations, /**< array of durations */
14079 int* demands, /**< array of demands */
14080 int capacity, /**< cumulative capacity */
14081 int hmin, /**< left bound of time axis to be considered (including hmin) */
14082 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14083 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14084 int inferinfo, /**< the user information */
14085 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14086 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14087 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14088 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14089 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14090 )
14091{
14092 SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14093 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14094
14095 return SCIP_OKAY;
14096}
14097
14098/** this method visualizes the cumulative structure in GML format */
14100 SCIP* scip, /**< SCIP data structure */
14101 SCIP_CONS* cons /**< cumulative constraint */
14102 )
14103{
14104 SCIP_CONSDATA* consdata;
14106 FILE* file;
14107 SCIP_VAR* var;
14108 char filename[SCIP_MAXSTRLEN];
14109 int nvars;
14110 int v;
14111
14112 SCIP_RETCODE retcode = SCIP_OKAY;
14113
14114 /* open file */
14115 (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14116 file = fopen(filename, "w");
14117
14118 /* check if the file was open */
14119 if( file == NULL )
14120 {
14121 SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14122 SCIPprintSysError(filename);
14123 return SCIP_FILECREATEERROR;
14124 }
14125
14126 consdata = SCIPconsGetData(cons);
14127 assert(consdata != NULL);
14128
14129 nvars = consdata->nvars;
14130
14132 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14133
14134 /* create opening of the GML format */
14136
14137 for( v = 0; v < nvars; ++v )
14138 {
14139 char color[SCIP_MAXSTRLEN];
14140
14141 var = consdata->vars[v];
14142 assert(var != NULL);
14143
14144 SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14145
14147 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14148 else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14149 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14150 else
14151 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14152
14153 SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14154 }
14155
14156 for( v = 0; v < nvars; ++v )
14157 {
14158 SCIP_VAR** vbdvars;
14159 int nvbdvars;
14160 int b;
14161
14162 var = consdata->vars[v];
14163 assert(var != NULL);
14164
14165 vbdvars = SCIPvarGetVlbVars(var);
14166 nvbdvars = SCIPvarGetNVlbs(var);
14167
14168 for( b = 0; b < nvbdvars; ++b )
14169 {
14170 if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14171 {
14172 SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14173 }
14174 }
14175
14176#ifdef SCIP_MORE_OUTPUT
14177 /* define to also output variable bounds */
14178 vbdvars = SCIPvarGetVubVars(var);
14179 nvbdvars = SCIPvarGetNVubs(var);
14180
14181 for( b = 0; b < nvbdvars; ++b )
14182 {
14183 if( SCIPhashtableExists(vars, vbdvars[b]) )
14184 {
14185 SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14186 }
14187 }
14188#endif
14189 }
14190
14191 /* create closing of the GML format */
14192 SCIPgmlWriteClosing(file);
14193TERMINATE:
14194 /* close file */
14195 fclose(file);
14196
14198
14199 return retcode;
14200}
14201
14202/** sets method to solve an individual cumulative condition */
14204 SCIP* scip, /**< SCIP data structure */
14205 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14206 )
14207{
14208 SCIP_CONSHDLR* conshdlr;
14209 SCIP_CONSHDLRDATA* conshdlrdata;
14210
14211 /* find the cumulative constraint handler */
14212 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14213 if( conshdlr == NULL )
14214 {
14215 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14216 return SCIP_PLUGINNOTFOUND;
14217 }
14218
14219 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14220 assert(conshdlrdata != NULL);
14221
14222 conshdlrdata->solveCumulative = solveCumulative;
14223
14224 return SCIP_OKAY;
14225}
14226
14227/** solves given cumulative condition as independent sub problem
14228 *
14229 * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14230 * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14231 * solver was interrupted.
14232 */
14234 SCIP* scip, /**< SCIP data structure */
14235 int njobs, /**< number of jobs (activities) */
14236 SCIP_Real* ests, /**< array with the earlier start time for each job */
14237 SCIP_Real* lsts, /**< array with the latest start time for each job */
14238 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14239 int* durations, /**< array of durations */
14240 int* demands, /**< array of demands */
14241 int capacity, /**< cumulative capacity */
14242 int hmin, /**< left bound of time axis to be considered (including hmin) */
14243 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14244 SCIP_Real timelimit, /**< time limit for solving in seconds */
14245 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14246 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14247 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14248 SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14249 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14250 SCIP_Bool* error /**< pointer to store if an error occurred */
14251 )
14252{
14253 SCIP_CONSHDLR* conshdlr;
14254 SCIP_CONSHDLRDATA* conshdlrdata;
14255
14256 (*solved) = TRUE;
14257 (*infeasible) = FALSE;
14258 (*unbounded) = FALSE;
14259 (*error) = FALSE;
14260
14261 if( njobs == 0 )
14262 return SCIP_OKAY;
14263
14264 /* find the cumulative constraint handler */
14265 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14266 if( conshdlr == NULL )
14267 {
14268 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14269 (*error) = TRUE;
14270 return SCIP_PLUGINNOTFOUND;
14271 }
14272
14273 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14274 assert(conshdlrdata != NULL);
14275
14276 /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14277 if( timelimit > 0.0 && memorylimit > 10 )
14278 {
14279 SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14280 hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14281 }
14282
14283 return SCIP_OKAY;
14284}
14285
14286/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14287 * completion time
14288 */
14290 SCIP* scip, /**< SCIP data structure */
14291 SCIP_PROFILE* profile, /**< resource profile */
14292 int nvars, /**< number of variables (jobs) */
14293 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14294 int* durations, /**< array containing corresponding durations */
14295 int* demands /**< array containing corresponding demands */
14296 )
14297{
14298 SCIP_VAR* var;
14299 SCIP_HASHMAP* addedvars;
14300 int* copydemands;
14301 int* perm;
14302 int duration;
14303 int impliedest;
14304 int est;
14305 int impliedlct;
14306 int lct;
14307 int v;
14308
14309 /* create hash map for variables which are added, mapping to their duration */
14311
14313 SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14314
14315 /* sort variables w.r.t. job demands */
14316 for( v = 0; v < nvars; ++v )
14317 {
14318 copydemands[v] = demands[v];
14319 perm[v] = v;
14320 }
14321 SCIPsortDownIntInt(copydemands, perm, nvars);
14322
14323 /* add each job with its earliest start and latest completion time into the resource profile */
14324 for( v = 0; v < nvars; ++v )
14325 {
14326 int idx;
14327
14328 idx = perm[v];
14329 assert(idx >= 0 && idx < nvars);
14330
14331 var = vars[idx];
14332 assert(var != NULL);
14333
14334 duration = durations[idx];
14335 assert(duration > 0);
14336
14338 SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14339
14341 SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14342
14343 if( impliedest < impliedlct )
14344 {
14345 SCIP_Bool infeasible;
14346 int pos;
14347
14348 SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14349 assert(!infeasible);
14350 assert(pos == -1);
14351 }
14352
14353 if( est == impliedest && lct == impliedlct )
14354 {
14355 SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14356 }
14357 }
14358
14359 SCIPfreeBufferArray(scip, &copydemands);
14360 SCIPfreeBufferArray(scip, &perm);
14361
14362 SCIPhashmapFree(&addedvars);
14363
14364 return SCIP_OKAY;
14365}
14366
14367/** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14369 SCIP* scip, /**< SCIP data structure */
14370 SCIP_PROFILE* profile, /**< worst case resource profile */
14371 int capacity /**< capacity to check */
14372 )
14373{
14374 int* timepoints;
14375 int* loads;
14376 int ntimepoints;
14377 int t;
14378
14379 ntimepoints = SCIPprofileGetNTimepoints(profile);
14380 timepoints = SCIPprofileGetTimepoints(profile);
14381 loads = SCIPprofileGetLoads(profile);
14382
14383 /* find first time point which potentially violates the capacity restriction */
14384 for( t = 0; t < ntimepoints - 1; ++t )
14385 {
14386 /* check if the time point exceed w.r.t. worst case profile the capacity */
14387 if( loads[t] > capacity )
14388 {
14389 assert(t == 0 || loads[t-1] <= capacity);
14390 return timepoints[t];
14391 }
14392 }
14393
14394 return INT_MAX;
14395}
14396
14397/** 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}*/
14399 SCIP* scip, /**< SCIP data structure */
14400 SCIP_PROFILE* profile, /**< worst case profile */
14401 int capacity /**< capacity to check */
14402 )
14403{
14404 int* timepoints;
14405 int* loads;
14406 int ntimepoints;
14407 int t;
14408
14409 ntimepoints = SCIPprofileGetNTimepoints(profile);
14410 timepoints = SCIPprofileGetTimepoints(profile);
14411 loads = SCIPprofileGetLoads(profile);
14412
14413 /* find last time point which potentially violates the capacity restriction */
14414 for( t = ntimepoints - 1; t >= 0; --t )
14415 {
14416 /* check if at time point t the worst case resource profile exceeds the capacity */
14417 if( loads[t] > capacity )
14418 {
14419 assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14420 return timepoints[t+1];
14421 }
14422 }
14423
14424 return INT_MIN;
14425}
static long bound
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
#define EVENTHDLR_NAME
SCIP_VAR ** b
#define EVENTHDLR_DESC
enum Proprule PROPRULE
Definition cons_and.c:172
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:96
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:89
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DESC
Definition cons_and.c:85
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:99
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:93
#define DEFAULT_PRESOLPAIRWISE
Definition cons_and.c:104
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:86
Proprule
Definition cons_and.c:165
#define CONSHDLR_PROPFREQ
Definition cons_and.c:90
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:98
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:91
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:87
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:94
#define CONSHDLR_NAME
Definition cons_and.c:84
#define CONSHDLR_DELAYPROP
Definition cons_and.c:95
static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
static int inferInfoGetData1(INFERINFO inferinfo)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define DEFAULT_USEBDWIDENING
#define DEFAULT_SEPAOLD
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
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)
#define DEFAULT_NORMALIZE
static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
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 getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
#define DEFAULT_DETECTVARBOUNDS
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)
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)
#define DEFAULT_TTEFINFER
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
#define DEFAULT_USECOVERCUTS
static SCIP_Longint computeCoreWithInterval(int begin, int end, int ect, int lst)
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
#define DEFAULT_LOCALCUTS
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)
#define DEFAULT_COEFTIGHTENING
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
static SCIP_RETCODE createPrecedenceCons(SCIP *scip, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, int distance)
#define DEFAULT_MAXNODES
static SCIP_Bool isConsIndependently(SCIP_CONS *cons)
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated, SCIP_Bool *cutoff)
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 void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
static void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
static void consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file)
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_RETCODE propagateTimetable(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
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 collectBranchingCands(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nbranchcands)
static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
static int computeEnergyContribution(SCIP_BTNODE *node)
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 presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
#define DEFAULT_EFINFER
static int boundedConvertRealToInt(SCIP *scip, SCIP_Real real)
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
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)
static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
#define DEFAULT_EFCHECK
static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
#define DEFAULT_DETECTDISJUNCTIVE
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
static INFERINFO getInferInfo(PROPRULE proprule, int data1, int data2)
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)
static int computeOverlap(int begin, int end, int est, int lst, int duration)
static SCIP_Longint computeTotalEnergy(int *durations, int *demands, int njobs)
static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
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 removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
static INFERINFO intToInferInfo(int i)
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 void updateEnvelope(SCIP *scip, SCIP_BTNODE *node)
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)
struct SCIP_NodeData SCIP_NODEDATA
#define DEFAULT_CUTSASCONSS
#define DEFAULT_DUALPRESOLVE
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 SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
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)
#define DEFAULT_TTEFCHECK
@ PROPRULE_3_TTEF
@ PROPRULE_0_INVALID
@ PROPRULE_1_CORETIMES
@ PROPRULE_2_EDGEFINDING
static void normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_Bool inferInfoIsValid(INFERINFO inferinfo)
static void computeCoreEnergyAfter(SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
static SCIP_RETCODE createCumulativeCons(SCIP *scip, const char *name, TCLIQUE_GRAPH *tcliquegraph, int *cliquenodes, int ncliquenodes)
static void collectDataTTEF(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int hmin, int hmax, int *permests, int *ests, int *permlcts, int *lcts, int *ects, int *lsts, int *flexenergies)
static SCIP_RETCODE 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)
static SCIP_RETCODE createCoverCutsTimepoint(SCIP *scip, SCIP_CONS *cons, int *startvalues, int time)
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 consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
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)
static int inferInfoGetData2(INFERINFO inferinfo)
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
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_RETCODE resolvePropagationCoretimes(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferdemand, int inferpeak, int relaxedpeak, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool usebdwidening, int *provedpeak, SCIP_Bool *explanation)
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE collectBinaryVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***vars, int **coefs, int *nvars, int *startindices, int curtime, int nstarted, int nfinished)
#define DEFAULT_USEADJUSTEDJOBS
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
static void collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, SCIP_Bool *cutoff)
static SCIP_RETCODE computeImpliedLct(SCIP *scip, SCIP_VAR *var, int duration, SCIP_HASHMAP *addedvars, int *lct)
static SCIP_RETCODE findCumulativeConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
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)
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
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 solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
#define DEFAULT_USEBINVARS
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
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 SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
#define DEFAULT_MAXTIME
static int computeEstOmegaset(SCIP *scip, int duration, int demand, int capacity, int est, int lct, int energy)
struct InferInfo INFERINFO
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_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA *nodedatas, int *nodedataidx, int *nnodedatas)
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
#define DEFAULT_FILLBRANCHCANDS
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
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 transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
static SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
#define DEFAULT_TTINFER
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE removeOversizedJobs(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *nchgcoefs, int *naddconss, SCIP_Bool *cutoff)
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
static int inferInfoToInt(INFERINFO inferinfo)
static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
static void traceLambdaEnergy(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
static SCIP_RETCODE separateConsBinaryRepresentation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
static void normalizeCumulativeCondition(SCIP *scip, int nvars, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
#define DEFAULT_DISJUNCTIVE
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss, SCIP_Bool *infeasible)
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
Constraint handler for knapsack constraints of the form , x binary and .
constraint handler for linking binary variables to a linking (continuous or integer) variable
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 NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Longint
Definition def.h:150
#define SCIP_INVALID
Definition def.h:187
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define SCIP_UNKNOWN
Definition def.h:188
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition def.h:385
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define MIN3(x, y, z)
Definition def.h:241
#define SCIPABORT()
Definition def.h:336
#define SCIP_LONGINT_MAX
Definition def.h:151
#define SCIP_CALL(x)
Definition def.h:364
#define SCIP_CALL_FINALLY(x, y)
Definition def.h:406
#define nnodes
Definition gastrans.c:74
static const NodeData nodedata[]
Definition gastrans.c:83
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition misc.c:9023
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition misc.c:8892
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition misc.c:9135
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition misc.c:9034
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition misc.c:8817
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition misc.c:8932
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition misc.c:8862
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition misc.c:8753
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition misc.c:8960
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition misc.c:8995
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition misc.c:8942
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition misc.c:9009
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition misc.c:8872
void SCIPbtFree(SCIP_BT **tree)
Definition misc.c:9053
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition misc.c:8882
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition misc.c:9158
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition misc.c:8922
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition misc.c:9145
int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
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 SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
#define SCIP_DECL_SOLVECUMULATIVE(x)
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE 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)
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip,)
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsolveCumulative(SCIP *scip, int njobs, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Real *objvals, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *linkvar, SCIP_VAR **binvars, SCIP_Real *vals, int nbinvars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
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)
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
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)
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
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 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)
SCIP_Real * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
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)
int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
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:713
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition misc.c:501
void SCIPgmlWriteClosing(FILE *file)
Definition misc.c:703
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition misc.c:687
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition misc.c:643
SCIP_Bool SCIPisTransformed(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_RETCODE SCIPfree(SCIP **scip)
SCIP_RETCODE SCIPcreate(SCIP **scip)
SCIP_STATUS SCIPgetStatus(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c:1907
int SCIPgetNCheckConss(SCIP *scip)
Definition scip_prob.c:3762
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3420
int SCIPgetNConss(SCIP *scip)
Definition scip_prob.c:3620
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition scip_prob.c:182
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3179
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3482
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2348
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2647
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:2298
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2535
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:4067
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
#define SCIPdebugMsg
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition misc.c:9197
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11162
SCIP_RETCODE SCIPapplyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_BOUNDTYPE boundtype, SCIP_Real bound, int maxproprounds, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Real *proplbs, SCIP_Real *propubs, SCIP_Bool *cutoff)
SCIP_RETCODE 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_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition scip_param.c:545
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition scip_param.c:487
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition scip_param.c:904
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition scip_param.c:307
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition scip_param.c:882
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition scip_param.c:661
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
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition scip_param.c:429
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition scip_param.c:603
void SCIPswapInts(int *value1, int *value2)
Definition misc.c:10485
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition misc.c:10511
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4350
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:492
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
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
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:323
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_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:808
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:785
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4320
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4340
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:854
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8423
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8652
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2536
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition scip_cons.c:1625
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition scip_cons.c:1296
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8522
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8702
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition scip_cons.c:1271
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition scip_cons.c:1321
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8582
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8454
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:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8612
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8632
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1812
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition scip_cons.c:1524
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition cons.c:8672
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1138
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
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:111
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition event.c:396
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:413
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition scip_mem.c:126
#define SCIPfreeBuffer(scip, ptr)
Definition scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition scip_mem.c:100
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
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:1398
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition scip_lp.c:2131
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1974
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition lp.c:17917
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition scip_sol.c:2986
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:451
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
SCIP_RETCODE SCIPsolve(SCIP *scip)
int SCIPgetNRuns(SCIP *scip)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition var.c:23546
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6401
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition var.c:24514
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5210
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition var.c:24536
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23674
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition scip_var.c:2119
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4380
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:23462
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:10550
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:7069
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23932
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6651
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition scip_var.c:728
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition scip_var.c:2499
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23684
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:5118
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:8621
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5296
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2872
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23694
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:24546
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:24556
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition var.c:23556
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:24526
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:120
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:11057
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
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:6964
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2736
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17319
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:184
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition var.c:24588
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition var.c:24568
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition var.c:24578
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4322
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition scip_var.c:10984
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition misc.c:7097
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition misc.c:6904
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition misc.c:6950
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition misc.c:6894
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition misc.c:6846
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition misc.c:6936
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition misc.c:6914
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition misc.c:6832
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition misc.c:6924
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition misc.c:7127
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition misc.c:6862
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition misc.c:5581
void SCIPsortInt(int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition misc.c:10985
void SCIPprintSysError(const char *message)
Definition misc.c:10719
return SCIP_OKAY
int c
SCIP_Bool cutoff
SCIP_Real objval
static SCIP_SOL * sol
int r
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
double real
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
#define SCIPdebugPrintCons(x, y, z)
#define SCIPstatisticPrintf
#define SCIPdebugMessage
Definition pub_message.h:96
#define SCIPstatistic(x)
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
default SCIP plugins
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
tclique user interface
#define TCLIQUE_GETWEIGHTS(x)
Definition tclique.h:105
#define TCLIQUE_GETNNODES(x)
Definition tclique.h:97
#define TCLIQUE_ISEDGE(x)
Definition tclique.h:115
#define TCLIQUE_SELECTADJNODES(x)
Definition tclique.h:130
enum TCLIQUE_Status TCLIQUE_STATUS
Definition tclique.h:68
int TCLIQUE_WEIGHT
Definition tclique.h:48
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)
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition tclique.h:49
#define TCLIQUE_NEWSOL(x)
Definition tclique.h:88
@ SCIP_CONFTYPE_PROPAGATION
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:867
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:769
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:506
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:885
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:612
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:845
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:561
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:676
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:810
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:179
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition type_event.h:125
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition type_lp.h:57
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:60
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
struct SCIP_Bt SCIP_BT
Definition type_misc.h:151
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
#define SCIP_DECL_SORTINDCOMP(x)
Definition type_misc.h:181
struct SCIP_BtNode SCIP_BTNODE
Definition type_misc.h:154
struct SCIP_HashTable SCIP_HASHTABLE
Definition type_misc.h:88
struct SCIP_Profile SCIP_PROFILE
Definition type_misc.h:139
@ SCIP_PARAMEMPHASIS_CPSOLVER
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_UNBOUNDED
Definition type_result.h:47
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_FILECREATEERROR
@ SCIP_INVALIDDATA
@ SCIP_PLUGINNOTFOUND
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ SCIP_STAGE_PROBLEM
Definition type_set.h:45
@ SCIP_STAGE_PRESOLVING
Definition type_set.h:49
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
@ SCIP_STAGE_TRANSFORMING
Definition type_set.h:46
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
@ SCIP_STATUS_OPTIMAL
Definition type_stat.h:43
@ SCIP_STATUS_TOTALNODELIMIT
Definition type_stat.h:50
@ SCIP_STATUS_BESTSOLLIMIT
Definition type_stat.h:60
@ SCIP_STATUS_SOLLIMIT
Definition type_stat.h:59
@ SCIP_STATUS_UNBOUNDED
Definition type_stat.h:45
@ SCIP_STATUS_UNKNOWN
Definition type_stat.h:42
@ SCIP_STATUS_PRIMALLIMIT
Definition type_stat.h:57
@ SCIP_STATUS_GAPLIMIT
Definition type_stat.h:56
@ SCIP_STATUS_USERINTERRUPT
Definition type_stat.h:47
@ SCIP_STATUS_TERMINATE
Definition type_stat.h:48
@ SCIP_STATUS_INFORUNBD
Definition type_stat.h:46
@ SCIP_STATUS_STALLNODELIMIT
Definition type_stat.h:52
@ SCIP_STATUS_TIMELIMIT
Definition type_stat.h:54
@ SCIP_STATUS_INFEASIBLE
Definition type_stat.h:44
@ SCIP_STATUS_NODELIMIT
Definition type_stat.h:49
@ SCIP_STATUS_DUALLIMIT
Definition type_stat.h:58
@ SCIP_STATUS_MEMLIMIT
Definition type_stat.h:55
@ SCIP_STATUS_RESTARTLIMIT
Definition type_stat.h:62
#define SCIP_PRESOLTIMING_ALWAYS
Definition type_timing.h:58
#define SCIP_PRESOLTIMING_MEDIUM
Definition type_timing.h:53
unsigned int SCIP_PRESOLTIMING
Definition type_timing.h:61
#define SCIP_PRESOLTIMING_FAST
Definition type_timing.h:52
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition type_timing.h:54
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
struct SCIP_BdChgIdx SCIP_BDCHGIDX
Definition type_var.h:151
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:65
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_FIXED
Definition type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_VARSTATUS_AGGREGATED
Definition type_var.h:55
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141