Scippy

SCIP

Solving Constraint Integer Programs

cons_cumulative.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_cumulative.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for cumulative constraints
28 * @author Timo Berthold
29 * @author Stefan Heinz
30 * @author Jens Schulz
31 *
32 * Given:
33 * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
34 * their demands \f$d_j\f$.
35 * - an integer resource capacity \f$C\f$
36 *
37 * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
38 *
39 * Separation:
40 * - can be done using binary start time model, see Pritskers, Watters and Wolfe
41 * - or by just separating relatively weak cuts on the integer start time variables
42 *
43 * Propagation:
44 * - time tabling, Klein & Scholl (1999)
45 * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
46 * (2009)
47 * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
48 *
49 */
50
51/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
52
53#include <assert.h>
54#include <string.h>
55
56#include "tclique/tclique.h"
58#include "scip/cons_linking.h"
59#include "scip/cons_knapsack.h"
60#include "scip/scipdefplugins.h"
61
62/**@name Constraint handler properties
63 *
64 * @{
65 */
66
67/* constraint handler properties */
68#define CONSHDLR_NAME "cumulative"
69#define CONSHDLR_DESC "cumulative constraint handler"
70#define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
71#define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
72#define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
73#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
74#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
75#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
76 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
77#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
78#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
79#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
80#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
81
82#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
83#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
84
85/**@} */
86
87/**@name Default parameter values
88 *
89 * @{
90 */
91
92/* default parameter values */
93#define DEFAULT_MAXTIME 2000000000 /** < maximum range for time horizon (to avoid integer overflow) */
94
95/* separation */
96#define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
97#define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
98#define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
99#define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
100#define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
101
102/* propagation */
103#define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
104#define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
105#define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
106#define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
107#define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
108#define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
109
110/* presolving */
111#define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
112#define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
113#define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
114#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
115#define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
116#define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
117#define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
118#define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
119
120/* enforcement */
121#define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
122
123/* conflict analysis */
124#define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
125
126/**@} */
127
128/**@name Event handler properties
129 *
130 * @{
131 */
132
133#define EVENTHDLR_NAME "cumulative"
134#define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
135
136/**@} */
137
138/*
139 * Data structures
140 */
141
142/** constraint data for cumulative constraints */
143struct SCIP_ConsData
144{
145 SCIP_VAR** vars; /**< array of variable representing the start time of each job */
146 SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
147 SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
148 SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
149 SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
150 SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
151 SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
152 int* demands; /**< array containing corresponding demands */
153 int* durations; /**< array containing corresponding durations */
154 SCIP_Real resstrength1; /**< stores the resource strength 1*/
155 SCIP_Real resstrength2; /**< stores the resource strength 2 */
156 SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
157 SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
158 SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
159 SCIP_Real estimatedstrength;
160 int nvars; /**< number of variables */
161 int varssize; /**< size of the arrays */
162 int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
163 int demandrowssize; /**< size of array rows of demand rows */
164 int nscoverrows; /**< number of rows of small cover cuts */
165 int scoverrowssize; /**< size of array of small cover cuts */
166 int nbcoverrows; /**< number of rows of big cover cuts */
167 int bcoverrowssize; /**< size of array of big cover cuts */
168 int capacity; /**< available cumulative capacity */
169
170 int hmin; /**< left bound of time axis to be considered (including hmin) */
171 int hmax; /**< right bound of time axis to be considered (not including hmax) */
172
173 unsigned int signature; /**< constraint signature which is need for pairwise comparison */
174
175 unsigned int validsignature:1; /**< is the signature valid */
176 unsigned int normalized:1; /**< is the constraint normalized */
177 unsigned int covercuts:1; /**< cover cuts are created? */
178 unsigned int propagated:1; /**< is constraint propagted */
179 unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
180 unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
181
182#ifdef SCIP_STATISTIC
183 int maxpeak;
184#endif
185};
186
187/** constraint handler data */
188struct SCIP_ConshdlrData
189{
190 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
191
192 SCIP_Bool usebinvars; /**< should the binary variables be used? */
193 SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
194 SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
195 SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
196 SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
197 SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
198 SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
199 SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
200 SCIP_Bool localcuts; /**< should cuts be added only locally? */
201 SCIP_Bool usecovercuts; /**< should covering cuts be added? */
202 SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
203
204 SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
205
206 SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
207 SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
208 SCIP_Bool normalize; /**< should demands and capacity be normalized? */
209 SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
210 SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
211 SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
212 SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
213 SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
214 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
215
216 int maxtime; /**< maximum range for time horizon (to avoid integer overflow) */
217 SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
218
219 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
220
221 /* statistic values which are collected if SCIP_STATISTIC is defined */
222#ifdef SCIP_STATISTIC
223 SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
224 SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
225 SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
226 SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
227 SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
228 SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
229 SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
230 SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
231 SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
232 SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
233
234 int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
235 int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
236 int nremovedlocks; /**< number of times a up or down lock was removed */
237 int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
238 int ndecomps; /**< number of times a constraint was decomposed */
239 int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
240 int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
241 int naddedvarbounds; /**< number of added variable bounds constraints */
242 int naddeddisjunctives; /**< number of added disjunctive constraints */
243
244 SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
245#endif
246};
247
248/**@name Inference Information Methods
249 *
250 * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
251 * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
252 * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
253 *
254 * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
255 * change and the earliest start and latest completion time of all jobs in the conflict set.
256 *
257 * @{
258 */
259
260/** Propagation rules */
262{
263 PROPRULE_0_INVALID = 0, /**< invalid inference information */
264 PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
265 PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
266 PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
268typedef enum Proprule PROPRULE;
269
270/** inference information */
271struct InferInfo
272{
273 union
274 {
275 /** struct to use the inference information */
276 struct
277 {
278 unsigned int proprule:2; /**< propagation rule that was applied */
279 unsigned int data1:15; /**< data field one */
280 unsigned int data2:15; /**< data field two */
281 } asbits;
282 int asint; /**< inference information as a single int value */
283 } val;
284};
285typedef struct InferInfo INFERINFO;
286
287/** converts an integer into an inference information */
288static
290 int i /**< integer to convert */
291 )
292{
293 INFERINFO inferinfo;
294
295 inferinfo.val.asint = i;
296
297 return inferinfo;
298}
299
300/** converts an inference information into an int */
301static
303 INFERINFO inferinfo /**< inference information to convert */
304 )
305{
306 return inferinfo.val.asint;
307}
308
309/** rounds real to int and maps for large absolute values */
310static
312 SCIP* scip, /**< scip data structure */
313 SCIP_Real real /**< double bound to convert */
314 )
315{
316 int maxval;
317
319
320 assert(maxval >= 0);
321
322 if( SCIPisInfinity(scip, real) || real > maxval )
323 {
324 return maxval;
325 }
326 if( SCIPisInfinity(scip, -real) || real < -maxval )
327 {
328 return -maxval;
329 }
331}
332
333/** returns the propagation rule stored in the inference information */
334static
336 INFERINFO inferinfo /**< inference information to convert */
337 )
338{
339 return (PROPRULE) inferinfo.val.asbits.proprule;
340}
341
342/** returns data field one of the inference information */
343static
345 INFERINFO inferinfo /**< inference information to convert */
346 )
347{
348 return (int) inferinfo.val.asbits.data1;
349}
350
351/** returns data field two of the inference information */
352static
354 INFERINFO inferinfo /**< inference information to convert */
355 )
356{
357 return (int) inferinfo.val.asbits.data2;
358}
359
360/** returns whether the inference information is valid */
361static
363 INFERINFO inferinfo /**< inference information to convert */
364 )
365{
366 return (inferinfo.val.asint != 0);
367}
368
369
370/** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
371static
373 PROPRULE proprule, /**< propagation rule that deduced the value */
374 int data1, /**< data field one */
375 int data2 /**< data field two */
376 )
377{
378 INFERINFO inferinfo;
379
380 /* check that the data members are in the range of the available bits */
381 if( proprule == PROPRULE_0_INVALID || data1 < 0 || data1 >= (1<<15) || data2 < 0 || data2 >= (1<<15) )
382 {
383 inferinfo.val.asint = 0;
384 assert(inferInfoGetProprule(inferinfo) == PROPRULE_0_INVALID);
385 assert(inferInfoIsValid(inferinfo) == FALSE);
386 }
387 else
388 {
389 inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
390 inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
391 inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
392 assert(inferInfoIsValid(inferinfo) == TRUE);
393 }
394
395 return inferinfo;
396}
397
398/**@} */
399
400/*
401 * Local methods
402 */
403
404/**@name Miscellaneous Methods
405 *
406 * @{
407 */
408
409#ifndef NDEBUG
410
411/** compute the core of a job which lies in certain interval [begin, end) */
412static
414 int begin, /**< begin of the interval */
415 int end, /**< end of the interval */
416 int ect, /**< earliest completion time */
417 int lst /**< latest start time */
418 )
419{
420 int core;
421
422 core = MAX(0, MIN(end, ect) - MAX(lst, begin));
423
424 return core;
425}
426#else
427#define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
428#endif
429
430/** returns the implied earliest start time */ /*lint -e{715}*/
431static
433 SCIP* scip, /**< SCIP data structure */
434 SCIP_VAR* var, /**< variable for which the implied est should be returned */
435 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
436 int* est /**< pointer to store the implied earliest start time */
437 )
438{ /*lint --e{715}*/
439#ifdef SCIP_DISABLED_CODE
440 /* there is a bug below */
441 SCIP_VAR** vbdvars;
442 SCIP_VAR* vbdvar;
443 SCIP_Real* vbdcoefs;
444 SCIP_Real* vbdconsts;
445 void* image;
446 int nvbdvars;
447 int v;
448#endif
449
451
452#ifdef SCIP_DISABLED_CODE
453 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
454
455 nvbdvars = SCIPvarGetNVlbs(var);
456 vbdvars = SCIPvarGetVlbVars(var);
457 vbdcoefs = SCIPvarGetVlbCoefs(var);
458 vbdconsts = SCIPvarGetVlbConstants(var);
459
460 for( v = 0; v < nvbdvars; ++v )
461 {
462 vbdvar = vbdvars[v];
463 assert(vbdvar != NULL);
464
465 image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
466
467 if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
468 {
469 int duration;
470 int vbdconst;
471
472 duration = (int)(size_t)image;
473 vbdconst = boundedConvertRealToInt(scip, vbdconsts[v]);
474
475 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
477 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
478
479 if( duration >= vbdconst )
480 {
481 int impliedest;
482
483 impliedest = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
484
485 if( (*est) < impliedest )
486 {
487 (*est) = impliedest;
488
489 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
490 }
491 }
492 }
493 }
494#endif
495
496 return SCIP_OKAY;
497}
498
499/** returns the implied latest completion time */ /*lint -e{715}*/
500static
502 SCIP* scip, /**< SCIP data structure */
503 SCIP_VAR* var, /**< variable for which the implied est should be returned */
504 int duration, /**< duration of the given job */
505 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
506 int* lct /**< pointer to store the implied latest completion time */
507 )
508{ /*lint --e{715}*/
509#ifdef SCIP_DISABLED_CODE
510 /* there is a bug below */
511 SCIP_VAR** vbdvars;
512 SCIP_VAR* vbdvar;
513 SCIP_Real* vbdcoefs;
514 SCIP_Real* vbdconsts;
515 int nvbdvars;
516 int v;
517#endif
518
519 (*lct) = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
520
521#ifdef SCIP_DISABLED_CODE
522 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
523
524 nvbdvars = SCIPvarGetNVubs(var);
525 vbdvars = SCIPvarGetVubVars(var);
526 vbdcoefs = SCIPvarGetVubCoefs(var);
527 vbdconsts = SCIPvarGetVubConstants(var);
528
529 for( v = 0; v < nvbdvars; ++v )
530 {
531 vbdvar = vbdvars[v];
532 assert(vbdvar != NULL);
533
534 if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
535 {
536 int vbdconst;
537
538 vbdconst = boundedConvertRealToInt(scip, -vbdconsts[v]);
539
540 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
542 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
543
544 if( duration >= -vbdconst )
545 {
546 int impliedlct;
547
548 impliedlct = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
549
550 if( (*lct) > impliedlct )
551 {
552 (*lct) = impliedlct;
553
554 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
555 }
556 }
557 }
558 }
559#endif
560
561 return SCIP_OKAY;
562}
563
564/** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
565static
567 SCIP* scip, /**< SCIP data structure */
568 SCIP_CONSDATA* consdata, /**< constraint data */
569 SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
570 int** coefs, /**< pointer to store the coefficients */
571 int* nvars, /**< number if collect binary variables */
572 int* startindices, /**< permutation with rspect to the start times */
573 int curtime, /**< current point in time */
574 int nstarted, /**< number of jobs that start before the curtime or at curtime */
575 int nfinished /**< number of jobs that finished before curtime or at curtime */
576 )
577{
578 int nrowvars;
579 int startindex;
580 int size;
581
582 size = 10;
583 nrowvars = 0;
584 startindex = nstarted - 1;
585
586 SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
587 SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
588
589 /* search for the (nstarted - nfinished) jobs which are active at curtime */
590 while( nstarted - nfinished > nrowvars )
591 {
592 SCIP_VAR* var;
593 int endtime;
594 int duration;
595 int demand;
596 int varidx;
597
598 /* collect job information */
599 varidx = startindices[startindex];
600 assert(varidx >= 0 && varidx < consdata->nvars);
601
602 var = consdata->vars[varidx];
603 duration = consdata->durations[varidx];
604 demand = consdata->demands[varidx];
605 assert(var != NULL);
606
607 endtime = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
608
609 /* check the end time of this job is larger than the curtime; in this case the job is still running */
610 if( endtime > curtime )
611 {
612 SCIP_VAR** binvars;
613 SCIP_Real* vals;
614 int nbinvars;
615 int start;
616 int end;
617 int b;
618
619 /* check if the linking constraints exists */
620 assert(SCIPexistsConsLinking(scip, var));
621 assert(SCIPgetConsLinking(scip, var) != NULL);
622 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
623
624 /* collect linking constraint information */
625 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
626 vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
627
628 start = curtime - duration + 1;
629 end = MIN(curtime, endtime - duration);
630
631 for( b = 0; b < nbinvars; ++b )
632 {
633 if( vals[b] < start )
634 continue;
635
636 if( vals[b] > end )
637 break;
638
639 assert(binvars[b] != NULL);
640
641 /* ensure array proper array size */
642 if( size == *nvars )
643 {
644 size *= 2;
645 SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
646 SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
647 }
648
649 (*vars)[*nvars] = binvars[b];
650 (*coefs)[*nvars] = demand;
651 (*nvars)++;
652 }
653 nrowvars++;
654 }
655
656 startindex--;
657 }
658
659 return SCIP_OKAY;
660}
661
662/** collect all integer variable which belong to jobs which can run at the point of interest */
663static
665 SCIP* scip, /**< SCIP data structure */
666 SCIP_CONSDATA* consdata, /**< constraint data */
667 SCIP_VAR*** activevars, /**< jobs that are currently running */
668 int* startindices, /**< permutation with rspect to the start times */
669 int curtime, /**< current point in time */
670 int nstarted, /**< number of jobs that start before the curtime or at curtime */
671 int nfinished, /**< number of jobs that finished before curtime or at curtime */
672 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
673 int* lhs /**< lhs for the new row sum of lbs + minoffset */
674 )
675{
676 SCIP_VAR* var;
677 int startindex;
678 int endtime;
679 int duration;
680 int starttime;
681
682 int varidx;
683 int sumofstarts;
684 int mindelta;
685 int counter;
686
687 assert(curtime >= consdata->hmin);
688 assert(curtime < consdata->hmax);
689
690 counter = 0;
691 sumofstarts = 0;
692
693 mindelta = INT_MAX;
694
695 startindex = nstarted - 1;
696
697 /* search for the (nstarted - nfinished) jobs which are active at curtime */
698 while( nstarted - nfinished > counter )
699 {
700 assert(startindex >= 0);
701
702 /* collect job information */
703 varidx = startindices[startindex];
704 assert(varidx >= 0 && varidx < consdata->nvars);
705
706 var = consdata->vars[varidx];
707 duration = consdata->durations[varidx];
708 assert(duration > 0);
709 assert(var != NULL);
710
711 if( lower )
713 else
715
716 endtime = MIN(starttime + duration, consdata->hmax);
717
718 /* check the end time of this job is larger than the curtime; in this case the job is still running */
719 if( endtime > curtime )
720 {
721 (*activevars)[counter] = var;
722 sumofstarts += starttime;
723 mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
724 counter++;
725 }
726
727 startindex--;
728 }
729
730 assert(mindelta > 0);
731 *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
732
733 return SCIP_OKAY;
734}
735
736/** initialize the sorted event point arrays */
737static
739 SCIP* scip, /**< SCIP data structure */
740 int nvars, /**< number of start time variables (activities) */
741 SCIP_VAR** vars, /**< array of start time variables */
742 int* durations, /**< array of durations per start time variable */
743 int* starttimes, /**< array to store sorted start events */
744 int* endtimes, /**< array to store sorted end events */
745 int* startindices, /**< permutation with rspect to the start times */
746 int* endindices, /**< permutation with rspect to the end times */
747 SCIP_Bool local /**< shall local bounds be used */
748 )
749{
750 SCIP_VAR* var;
751 int j;
752
753 assert(vars != NULL || nvars == 0);
754
755 /* assign variables, start and endpoints to arrays */
756 for ( j = 0; j < nvars; ++j )
757 {
758 assert(vars != NULL);
759
760 var = vars[j];
761 assert(var != NULL);
762
763 if( local )
764 starttimes[j] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var));
765 else
766 starttimes[j] = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var));
767
768 startindices[j] = j;
769
770 if( local )
771 endtimes[j] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
772 else
773 endtimes[j] = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
774
775 endindices[j] = j;
776 }
777
778 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
779 SCIPsortIntInt(starttimes, startindices, j);
780 SCIPsortIntInt(endtimes, endindices, j);
781}
782
783/** initialize the sorted event point arrays w.r.t. the given primal solutions */
784static
786 SCIP* scip, /**< SCIP data structure */
787 SCIP_SOL* sol, /**< solution */
788 int nvars, /**< number of start time variables (activities) */
789 SCIP_VAR** vars, /**< array of start time variables */
790 int* durations, /**< array of durations per start time variable */
791 int* starttimes, /**< array to store sorted start events */
792 int* endtimes, /**< array to store sorted end events */
793 int* startindices, /**< permutation with rspect to the start times */
794 int* endindices /**< permutation with rspect to the end times */
795 )
796{
797 SCIP_VAR* var;
798 int j;
799
800 assert(vars != NULL || nvars == 0);
801
802 /* assign variables, start and endpoints to arrays */
803 for ( j = 0; j < nvars; ++j )
804 {
805 assert(vars != NULL);
806
807 var = vars[j];
808 assert(var != NULL);
809
810 starttimes[j] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
811 startindices[j] = j;
812
813 endtimes[j] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
814 endindices[j] = j;
815 }
816
817 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
818 SCIPsortIntInt(starttimes, startindices, j);
819 SCIPsortIntInt(endtimes, endindices, j);
820}
821
822/** initialize the sorted event point arrays
823 *
824 * @todo Check the separation process!
825 */
826static
828 SCIP* scip, /**< SCIP data structure */
829 SCIP_CONSDATA* consdata, /**< constraint data */
830 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
831 int* starttimes, /**< array to store sorted start events */
832 int* endtimes, /**< array to store sorted end events */
833 int* startindices, /**< permutation with rspect to the start times */
834 int* endindices, /**< permutation with rspect to the end times */
835 int* nvars, /**< number of variables that are integral */
836 SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
837 )
838{
839 SCIP_VAR* var;
840 int tmpnvars;
841 int j;
842
843 tmpnvars = consdata->nvars;
844 *nvars = 0;
845
846 /* assign variables, start and endpoints to arrays */
847 for ( j = 0; j < tmpnvars; ++j )
848 {
849 var = consdata->vars[j];
850 assert(var != NULL);
851 assert(consdata->durations[j] > 0);
852 assert(consdata->demands[j] > 0);
853
854 if( lower )
855 {
856 /* only consider jobs that are at their lower or upper bound */
857 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
858 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
859 continue;
860
861 starttimes[*nvars] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
862 startindices[*nvars] = j;
863
864 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
865 endindices[*nvars] = j;
866
867 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
868 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
869 consdata->durations[j],
870 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
871 consdata->demands[startindices[*nvars]]);
872
873 (*nvars)++;
874 }
875 else
876 {
877 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
878 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
879 continue;
880
881 starttimes[*nvars] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
882 startindices[*nvars] = j;
883
884 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
885 endindices[*nvars] = j;
886
887 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
888 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
889 consdata->durations[j],
890 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
891 consdata->demands[startindices[*nvars]]);
892
893 (*nvars)++;
894 }
895 }
896
897 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
898 SCIPsortIntInt(starttimes, startindices, *nvars);
899 SCIPsortIntInt(endtimes, endindices, *nvars);
900
901#ifdef SCIP_DEBUG
902 SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
903
904 for ( j = 0; j < *nvars; ++j )
905 {
906 SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
907 startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
908 consdata->demands[startindices[j]]);
909 }
910
911 for ( j = 0; j < *nvars; ++j )
912 {
913 SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
914 consdata->demands[endindices[j]]);
915 }
916#endif
917}
918
919#ifdef SCIP_STATISTIC
920/** this method checks for relevant intervals for energetic reasoning */
921static
922SCIP_RETCODE computeRelevantEnergyIntervals(
923 SCIP* scip, /**< SCIP data structure */
924 int nvars, /**< number of start time variables (activities) */
925 SCIP_VAR** vars, /**< array of start time variables */
926 int* durations, /**< array of durations */
927 int* demands, /**< array of demands */
928 int capacity, /**< cumulative capacity */
929 int hmin, /**< left bound of time axis to be considered (including hmin) */
930 int hmax, /**< right bound of time axis to be considered (not including hmax) */
931 int** timepoints, /**< array to store relevant points in time */
932 SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
933 int* ntimepoints, /**< pointer to store the number of timepoints */
934 int* maxdemand, /**< pointer to store maximum over all demands */
935 SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
936 )
937{
938 int* starttimes; /* stores when each job is starting */
939 int* endtimes; /* stores when each job ends */
940 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
941 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
942
943 SCIP_Real totaldemand;
944 int curtime; /* point in time which we are just checking */
945 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
946
947 int j;
948
949 assert( scip != NULL );
950 assert(durations != NULL);
951 assert(demands != NULL);
952 assert(capacity >= 0);
953
954 /* if no activities are associated with this cumulative then this constraint is redundant */
955 if( nvars == 0 )
956 return SCIP_OKAY;
957
958 assert(vars != NULL);
959
960 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
961 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
962 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
963 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
964
965 /* create event point arrays */
966 createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
967
968 endindex = 0;
969 totaldemand = 0.0;
970
971 *ntimepoints = 0;
972 (*timepoints)[0] = starttimes[0];
973 (*cumulativedemands)[0] = 0;
974 *maxdemand = 0;
975
976 /* check each startpoint of a job whether the capacity is kept or not */
977 for( j = 0; j < nvars; ++j )
978 {
979 int lct;
980 int idx;
981
982 curtime = starttimes[j];
983
984 if( curtime >= hmax )
985 break;
986
987 /* free all capacity usages of jobs the are no longer running */
988 while( endindex < nvars && endtimes[endindex] <= curtime )
989 {
990 int est;
991
992 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
993 {
994 (*ntimepoints)++;
995 (*timepoints)[*ntimepoints] = endtimes[endindex];
996 (*cumulativedemands)[*ntimepoints] = 0;
997 }
998
999 idx = endindices[endindex];
1001 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
1002 endindex++;
1003
1004 (*cumulativedemands)[*ntimepoints] = totaldemand;
1005 }
1006
1007 idx = startindices[j];
1008 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
1009 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
1010
1011 if( (*timepoints)[*ntimepoints] < curtime )
1012 {
1013 (*ntimepoints)++;
1014 (*timepoints)[*ntimepoints] = curtime;
1015 (*cumulativedemands)[*ntimepoints] = 0;
1016 }
1017
1018 (*cumulativedemands)[*ntimepoints] = totaldemand;
1019
1020 /* add the relative capacity requirements for all job which start at the curtime */
1021 while( j+1 < nvars && starttimes[j+1] == curtime )
1022 {
1023 ++j;
1024 idx = startindices[j];
1025 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
1026 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
1027
1028 (*cumulativedemands)[*ntimepoints] = totaldemand;
1029 }
1030 } /*lint --e{850}*/
1031
1032 /* free all capacity usages of jobs that are no longer running */
1033 while( endindex < nvars/* && endtimes[endindex] < hmax*/)
1034 {
1035 int est;
1036 int idx;
1037
1038 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
1039 {
1040 (*ntimepoints)++;
1041 (*timepoints)[*ntimepoints] = endtimes[endindex];
1042 (*cumulativedemands)[*ntimepoints] = 0;
1043 }
1044
1045 idx = endindices[endindex];
1047 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
1048 (*cumulativedemands)[*ntimepoints] = totaldemand;
1049
1050 ++endindex;
1051 }
1052
1053 (*ntimepoints)++;
1054 /* compute minimum free capacity */
1055 (*minfreecapacity) = INT_MAX;
1056 for( j = 0; j < *ntimepoints; ++j )
1057 {
1058 if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1059 *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1060 }
1061
1062 /* free buffer arrays */
1063 SCIPfreeBufferArray(scip, &endindices);
1064 SCIPfreeBufferArray(scip, &startindices);
1065 SCIPfreeBufferArray(scip, &endtimes);
1066 SCIPfreeBufferArray(scip, &starttimes);
1067
1068 return SCIP_OKAY;
1069}
1070
1071/** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1072static
1073SCIP_RETCODE evaluateCumulativeness(
1074 SCIP* scip, /**< pointer to scip */
1075 SCIP_CONS* cons /**< cumulative constraint */
1076 )
1077{
1078 SCIP_CONSDATA* consdata;
1079 int nvars;
1080 int v;
1081 int capacity;
1082
1083 /* output values: */
1084 SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1085 SCIP_Real cumfactor1;
1086 SCIP_Real resstrength1; /* overall strength */
1087 SCIP_Real resstrength2; /* timepoint wise maximum */
1088
1089 /* helpful variables: */
1090 SCIP_Real globalpeak;
1091 SCIP_Real globalmaxdemand;
1092
1093 /* get constraint data structure */
1094 consdata = SCIPconsGetData(cons);
1095 assert(consdata != NULL);
1096
1097 nvars = consdata->nvars;
1098 capacity = consdata->capacity;
1099 globalpeak = 0.0;
1100 globalmaxdemand = 0.0;
1101
1102 disjfactor2 = 0.0;
1103 cumfactor1 = 0.0;
1104 resstrength2 = 0.0;
1105
1106 /* check each starting time (==each job, but inefficient) */
1107 for( v = 0; v < nvars; ++v )
1108 {
1109 SCIP_Real peak;
1110 SCIP_Real maxdemand;
1111 SCIP_Real deltademand;
1112 int ndemands;
1113 int nlarge;
1114
1115 int timepoint;
1116 int j;
1117 timepoint = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1118 peak = consdata->demands[v];
1119 ndemands = 1;
1120 maxdemand = 0;
1121 nlarge = 0;
1122
1123 if( consdata->demands[v] > capacity / 3 )
1124 nlarge++;
1125
1126 for( j = 0; j < nvars; ++j )
1127 {
1128 int lb;
1129
1130 if( j == v )
1131 continue;
1132
1133 maxdemand = 0.0;
1134 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1135
1136 if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1137 {
1138 peak += consdata->demands[j];
1139 ndemands++;
1140
1141 if( consdata->demands[j] > consdata->capacity / 3 )
1142 nlarge++;
1143 }
1144 }
1145
1146 deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1147 globalpeak = MAX(globalpeak, peak);
1148 globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1149
1150 if( peak > capacity )
1151 {
1152 disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1153 cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1154 resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1155 }
1156 }
1157
1158 resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1159
1160 consdata->maxpeak = boundedConvertRealToInt(scip, globalpeak);
1161 consdata->disjfactor2 = disjfactor2;
1162 consdata->cumfactor1 = cumfactor1;
1163 consdata->resstrength2 = resstrength2;
1164 consdata->resstrength1 = resstrength1;
1165
1166 /* get estimated res strength */
1167 {
1168 int* timepoints;
1169 SCIP_Real* estimateddemands;
1170 int ntimepoints;
1171 int maxdemand;
1172 SCIP_Real minfreecapacity;
1173
1174 SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1175 SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1176
1177 ntimepoints = 0;
1178 minfreecapacity = INT_MAX;
1179
1180 SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1181 consdata->durations, consdata->demands,
1182 capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1183 &ntimepoints, &maxdemand, &minfreecapacity) );
1184
1185 /* free buffer arrays */
1186 SCIPfreeBufferArray(scip, &estimateddemands);
1187 SCIPfreeBufferArray(scip, &timepoints);
1188
1189 consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1190 }
1191
1192 SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1193 SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1194 consdata->estimatedstrength);
1195
1196 return SCIP_OKAY;
1197}
1198#endif
1199
1200/** gets the active variables together with the constant */
1201static
1203 SCIP* scip, /**< SCIP data structure */
1204 SCIP_VAR** var, /**< pointer to store the active variable */
1205 int* scalar, /**< pointer to store the scalar */
1206 int* constant /**< pointer to store the constant */
1207 )
1208{
1209 if( !SCIPvarIsActive(*var) )
1210 {
1211 SCIP_Real realscalar;
1212 SCIP_Real realconstant;
1213
1214 realscalar = 1.0;
1215 realconstant = 0.0;
1216
1218
1219 /* transform variable to active variable */
1220 SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1221 assert(!SCIPisZero(scip, realscalar));
1222 assert(SCIPvarIsActive(*var));
1223
1224 if( realconstant < 0.0 )
1225 (*constant) = -boundedConvertRealToInt(scip, -realconstant);
1226 else
1227 (*constant) = boundedConvertRealToInt(scip, realconstant);
1228
1229 if( realscalar < 0.0 )
1230 (*scalar) = -boundedConvertRealToInt(scip, -realscalar);
1231 else
1232 (*scalar) = boundedConvertRealToInt(scip, realscalar);
1233 }
1234 else
1235 {
1236 (*scalar) = 1;
1237 (*constant) = 0;
1238 }
1239
1240 assert(*scalar != 0);
1241
1242 return SCIP_OKAY;
1243}
1244
1245/** computes the total energy of all jobs */
1246static
1248 int* durations, /**< array of job durations */
1249 int* demands, /**< array of job demands */
1250 int njobs /**< number of jobs */
1251 )
1252{
1253 SCIP_Longint energy;
1254 int j;
1255
1256 energy = 0;
1257
1258 for( j = 0; j < njobs; ++j )
1259 energy += (SCIP_Longint) durations[j] * demands[j];
1260
1261 return energy;
1262}
1263
1264/**@} */
1265
1266/**@name Default method to solve a cumulative condition
1267 *
1268 * @{
1269 */
1270
1271/** setup and solve subscip to solve single cumulative condition */
1272static
1274 SCIP* subscip, /**< subscip data structure */
1275 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1276 int* durations, /**< array of durations */
1277 int* demands, /**< array of demands */
1278 int njobs, /**< number of jobs (activities) */
1279 int capacity, /**< cumulative capacity */
1280 int hmin, /**< left bound of time axis to be considered (including hmin) */
1281 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1282 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1283 SCIP_Real timelimit, /**< time limit for solving in seconds */
1284 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1285 SCIP_Real* ests, /**< array of earliest start times for each job */
1286 SCIP_Real* lsts, /**< array of latest start times for each job */
1287 SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1288 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1289 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1290 SCIP_Bool* error /**< pointer to store if an error occurred */
1291 )
1292{
1293 SCIP_VAR** subvars;
1294 SCIP_CONS* cons;
1295
1296 char name[SCIP_MAXSTRLEN];
1297 int v;
1298 SCIP_RETCODE retcode;
1299
1300 assert(subscip != NULL);
1301
1302 /* copy all plugins */
1304
1305 /* create the subproblem */
1306 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1307
1308 SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1309
1310 /* create for each job a start time variable */
1311 for( v = 0; v < njobs; ++v )
1312 {
1313 SCIP_Real objval;
1314
1315 /* construct variable name */
1316 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1317
1318 if( objvals == NULL )
1319 objval = 0.0;
1320 else
1321 objval = objvals[v];
1322
1323 SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1324 SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1325 }
1326
1327 /* create cumulative constraint */
1328 SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1329 njobs, subvars, durations, demands, capacity) );
1330
1331 /* set effective horizon */
1332 SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1333 SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1334
1335 /* add cumulative constraint */
1336 SCIP_CALL( SCIPaddCons(subscip, cons) );
1337 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1338
1339 /* set CP solver settings
1340 *
1341 * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1342 * time limit.
1343 */
1345
1346 /* do not abort subproblem on CTRL-C */
1347 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1348
1349 /* disable output to console */
1350 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1351
1352 /* set limits for the subproblem */
1353 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1354 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1355 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1356
1357 /* forbid recursive call of heuristics and separators solving subMIPs */
1358 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1359
1360 /* solve single cumulative constraint by branch and bound */
1361 retcode = SCIPsolve(subscip);
1362
1363 if( retcode != SCIP_OKAY )
1364 (*error) = TRUE;
1365 else
1366 {
1367 SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1368
1369 /* evaluated solution status */
1370 switch( SCIPgetStatus(subscip) )
1371 {
1374 (*infeasible) = TRUE;
1375 (*solved) = TRUE;
1376 break;
1378 (*unbounded) = TRUE;
1379 (*solved) = TRUE;
1380 break;
1382 {
1383 SCIP_SOL* sol;
1384 SCIP_Real solval;
1385
1386 sol = SCIPgetBestSol(subscip);
1387 assert(sol != NULL);
1388
1389 for( v = 0; v < njobs; ++v )
1390 {
1391 solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1392
1393 ests[v] = solval;
1394 lsts[v] = solval;
1395 }
1396 (*solved) = TRUE;
1397 break;
1398 }
1405 /* transfer the global bound changes */
1406 for( v = 0; v < njobs; ++v )
1407 {
1408 ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1409 lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1410 }
1411 (*solved) = FALSE;
1412 break;
1413
1422 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1423 return SCIP_INVALIDDATA;
1424 }
1425 }
1426
1427 /* release all variables */
1428 for( v = 0; v < njobs; ++v )
1429 {
1430 SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1431 }
1432
1433 SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1434
1435 return SCIP_OKAY;
1436}
1437
1438/** solve single cumulative condition using SCIP and a single cumulative constraint */
1439static
1440SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1441{
1442 SCIP* subscip;
1443
1444 SCIP_RETCODE retcode;
1445
1446 assert(njobs > 0);
1447
1448 (*solved) = FALSE;
1449 (*infeasible) = FALSE;
1450 (*unbounded) = FALSE;
1451 (*error) = FALSE;
1452
1453 SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1454
1455 /* initialize the sub-problem */
1456 SCIP_CALL( SCIPcreate(&subscip) );
1457
1458 /* create and solve the subproblem. catch possible errors */
1459 retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1460 njobs, capacity, hmin, hmax,
1461 maxnodes, timelimit, memorylimit,
1462 ests, lsts,
1463 infeasible, unbounded, solved, error);
1464
1465 /* free the subscip in any case */
1466 SCIP_CALL( SCIPfree(&subscip) );
1467
1468 SCIP_CALL( retcode );
1469
1470 return SCIP_OKAY;
1471}
1472
1473#ifdef SCIP_DISABLED_CODE
1474/* The following code should work, but is currently not used. */
1475
1476/** solve single cumulative condition using SCIP and the time indexed formulation */
1477static
1478SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1479{
1480 SCIP* subscip;
1481 SCIP_VAR*** binvars;
1482 SCIP_RETCODE retcode;
1483 char name[SCIP_MAXSTRLEN];
1484 int minest;
1485 int maxlct;
1486 int t;
1487 int v;
1488
1489 assert(njobs > 0);
1490
1491 (*solved) = FALSE;
1492 (*infeasible) = FALSE;
1493 (*unbounded) = FALSE;
1494 (*error) = FALSE;
1495
1496 SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1497
1498 /* initialize the sub-problem */
1499 SCIP_CALL( SCIPcreate(&subscip) );
1500
1501 /* copy all plugins */
1503
1504 /* create the subproblem */
1505 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1506
1507 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1508
1509 minest = INT_MAX;
1510 maxlct = INT_MIN;
1511
1512 /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1513 * partitioning constrain which forces that job starts
1514 */
1515 for( v = 0; v < njobs; ++v )
1516 {
1517 SCIP_CONS* cons;
1518 SCIP_Real objval;
1519 int timeinterval;
1520 int est;
1521 int lst;
1522
1523 if( objvals == NULL )
1524 objval = 0.0;
1525 else
1526 objval = objvals[v];
1527
1528 est = ests[v];
1529 lst = lsts[v];
1530
1531 /* compute number of possible start points */
1532 timeinterval = lst - est + 1;
1533 assert(timeinterval > 0);
1534
1535 /* compute the smallest earliest start time and largest latest completion time */
1536 minest = MIN(minest, est);
1537 maxlct = MAX(maxlct, lst + durations[v]);
1538
1539 /* construct constraint name */
1540 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1541
1542 SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1543
1544 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1545
1546 for( t = 0; t < timeinterval; ++t )
1547 {
1548 SCIP_VAR* binvar;
1549
1550 /* construct varibale name */
1551 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1552
1553 SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1554 SCIP_CALL( SCIPaddVar(subscip, binvar) );
1555
1556 /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1557 SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1558
1559 binvars[v][t] = binvar;
1560 }
1561
1562 /* add and release the set partitioning constraint */
1563 SCIP_CALL( SCIPaddCons(subscip, cons) );
1564 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1565 }
1566
1567 /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1568 hmin = MAX(hmin, minest);
1569 hmax = MIN(hmax, maxlct);
1570 assert(hmin > INT_MIN);
1571 assert(hmax < INT_MAX);
1572 assert(hmin < hmax);
1573
1574 /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1575 for( t = hmin; t < hmax; ++t )
1576 {
1577 SCIP_CONS* cons;
1578
1579 /* construct constraint name */
1580 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1581
1582 /* create an empty knapsack constraint */
1583 SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1584
1585 /* add all jobs which potentially can be processed at that time point */
1586 for( v = 0; v < njobs; ++v )
1587 {
1588 int duration;
1589 int demand;
1590 int start;
1591 int end;
1592 int est;
1593 int lst;
1594 int k;
1595
1596 est = ests[v];
1597 lst = lsts[v] ;
1598
1599 duration = durations[v];
1600 assert(duration > 0);
1601
1602 /* check if the varibale is processed potentially at time point t */
1603 if( t < est || t >= lst + duration )
1604 continue;
1605
1606 demand = demands[v];
1607 assert(demand >= 0);
1608
1609 start = MAX(t - duration + 1, est);
1610 end = MIN(t, lst);
1611
1612 assert(start <= end);
1613
1614 for( k = start; k <= end; ++k )
1615 {
1616 assert(binvars[v][k] != NULL);
1617 SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1618 }
1619 }
1620
1621 /* add and release the knapsack constraint */
1622 SCIP_CALL( SCIPaddCons(subscip, cons) );
1623 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1624 }
1625
1626 /* do not abort subproblem on CTRL-C */
1627 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1628
1629 /* disable output to console */
1630 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1631
1632 /* set limits for the subproblem */
1633 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1634 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1635 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1636
1637 /* solve single cumulative constraint by branch and bound */
1638 retcode = SCIPsolve(subscip);
1639
1640 if( retcode != SCIP_OKAY )
1641 (*error) = TRUE;
1642 else
1643 {
1644 SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1645
1646 /* evaluated solution status */
1647 switch( SCIPgetStatus(subscip) )
1648 {
1651 (*infeasible) = TRUE;
1652 (*solved) = TRUE;
1653 break;
1655 (*unbounded) = TRUE;
1656 (*solved) = TRUE;
1657 break;
1659 {
1660 SCIP_SOL* sol;
1661
1662 sol = SCIPgetBestSol(subscip);
1663 assert(sol != NULL);
1664
1665 for( v = 0; v < njobs; ++v )
1666 {
1667 int timeinterval;
1668 int est;
1669 int lst;
1670
1671 est = ests[v];
1672 lst = lsts[v];
1673
1674 /* compute number of possible start points */
1675 timeinterval = lst - est + 1;
1676
1677 /* check which binary varibale is set to one */
1678 for( t = 0; t < timeinterval; ++t )
1679 {
1680 if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1681 {
1682 ests[v] = est + t;
1683 lsts[v] = est + t;
1684 break;
1685 }
1686 }
1687 }
1688
1689 (*solved) = TRUE;
1690 break;
1691 }
1697 /* transfer the global bound changes */
1698 for( v = 0; v < njobs; ++v )
1699 {
1700 int timeinterval;
1701 int est;
1702 int lst;
1703
1704 est = ests[v];
1705 lst = lsts[v];
1706
1707 /* compute number of possible start points */
1708 timeinterval = lst - est + 1;
1709
1710 /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1711 for( t = 0; t < timeinterval; ++t )
1712 {
1713 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1714 {
1715 ests[v] = est + t;
1716 break;
1717 }
1718 }
1719
1720 /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1721 for( t = timeinterval - 1; t >= 0; --t )
1722 {
1723 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1724 {
1725 lsts[v] = est + t;
1726 break;
1727 }
1728 }
1729 }
1730 (*solved) = FALSE;
1731 break;
1732
1738 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1739 return SCIP_INVALIDDATA;
1740 }
1741 }
1742
1743 /* release all variables */
1744 for( v = 0; v < njobs; ++v )
1745 {
1746 int timeinterval;
1747 int est;
1748 int lst;
1749
1750 est = ests[v];
1751 lst = lsts[v];
1752
1753 /* compute number of possible start points */
1754 timeinterval = lst - est + 1;
1755
1756 for( t = 0; t < timeinterval; ++t )
1757 {
1758 SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1759 }
1760 SCIPfreeBufferArray(subscip, &binvars[v]);
1761 }
1762
1763 SCIPfreeBufferArray(subscip, &binvars);
1764
1765 SCIP_CALL( SCIPfree(&subscip) );
1766
1767 return SCIP_OKAY;
1768}
1769#endif
1770
1771/**@} */
1772
1773/**@name Constraint handler data
1774 *
1775 * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1776 * handler.
1777 *
1778 * @{
1779 */
1780
1781/** creates constaint handler data for cumulative constraint handler */
1782static
1784 SCIP* scip, /**< SCIP data structure */
1785 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1786 SCIP_EVENTHDLR* eventhdlr /**< event handler */
1787 )
1788{
1789 /* create precedence constraint handler data */
1790 assert(scip != NULL);
1791 assert(conshdlrdata != NULL);
1792 assert(eventhdlr != NULL);
1793
1794 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1795
1796 /* set event handler for checking if bounds of start time variables are tighten */
1797 (*conshdlrdata)->eventhdlr = eventhdlr;
1798
1799 /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1800 (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1801
1802#ifdef SCIP_STATISTIC
1803 (*conshdlrdata)->nlbtimetable = 0;
1804 (*conshdlrdata)->nubtimetable = 0;
1805 (*conshdlrdata)->ncutofftimetable = 0;
1806 (*conshdlrdata)->nlbedgefinder = 0;
1807 (*conshdlrdata)->nubedgefinder = 0;
1808 (*conshdlrdata)->ncutoffedgefinder = 0;
1809 (*conshdlrdata)->ncutoffoverload = 0;
1810 (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1811
1812 (*conshdlrdata)->nirrelevantjobs = 0;
1813 (*conshdlrdata)->nalwaysruns = 0;
1814 (*conshdlrdata)->nremovedlocks = 0;
1815 (*conshdlrdata)->ndualfixs = 0;
1816 (*conshdlrdata)->ndecomps = 0;
1817 (*conshdlrdata)->ndualbranchs = 0;
1818 (*conshdlrdata)->nallconsdualfixs = 0;
1819 (*conshdlrdata)->naddedvarbounds = 0;
1820 (*conshdlrdata)->naddeddisjunctives = 0;
1821#endif
1822
1823 return SCIP_OKAY;
1824}
1825
1826/** frees constraint handler data for logic or constraint handler */
1827static
1829 SCIP* scip, /**< SCIP data structure */
1830 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1831 )
1832{
1833 assert(conshdlrdata != NULL);
1834 assert(*conshdlrdata != NULL);
1835
1836 SCIPfreeBlockMemory(scip, conshdlrdata);
1837}
1838
1839/**@} */
1840
1841
1842/**@name Constraint data methods
1843 *
1844 * @{
1845 */
1846
1847/** catches bound change events for all variables in transformed cumulative constraint */
1848static
1850 SCIP* scip, /**< SCIP data structure */
1851 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1852 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1853 )
1854{
1855 int v;
1856
1857 assert(scip != NULL);
1858 assert(consdata != NULL);
1859 assert(eventhdlr != NULL);
1860
1861 /* catch event for every single variable */
1862 for( v = 0; v < consdata->nvars; ++v )
1863 {
1864 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1865 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1866 }
1867
1868 return SCIP_OKAY;
1869}
1870
1871/** drops events for variable at given position */
1872static
1874 SCIP* scip, /**< SCIP data structure */
1875 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1876 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1877 int pos /**< array position of variable to catch bound change events for */
1878 )
1879{
1880 assert(scip != NULL);
1881 assert(consdata != NULL);
1882 assert(eventhdlr != NULL);
1883 assert(0 <= pos && pos < consdata->nvars);
1884 assert(consdata->vars[pos] != NULL);
1885
1886 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1887 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1888
1889 return SCIP_OKAY;
1890}
1891
1892/** drops bound change events for all variables in transformed linear constraint */
1893static
1895 SCIP* scip, /**< SCIP data structure */
1896 SCIP_CONSDATA* consdata, /**< linear constraint data */
1897 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1898 )
1899{
1900 int v;
1901
1902 assert(scip != NULL);
1903 assert(consdata != NULL);
1904
1905 /* drop event of every single variable */
1906 for( v = 0; v < consdata->nvars; ++v )
1907 {
1908 SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1909 }
1910
1911 return SCIP_OKAY;
1912}
1913
1914/** initialize variable lock data structure */
1915static
1917 SCIP_CONSDATA* consdata, /**< constraint data */
1918 SCIP_Bool locked /**< should the variable be locked? */
1919 )
1920{
1921 int nvars;
1922 int v;
1923
1924 nvars = consdata->nvars;
1925
1926 /* initialize locking arrays */
1927 for( v = 0; v < nvars; ++v )
1928 {
1929 consdata->downlocks[v] = locked;
1930 consdata->uplocks[v] = locked;
1931 }
1932}
1933
1934/** creates constraint data of cumulative constraint */
1935static
1937 SCIP* scip, /**< SCIP data structure */
1938 SCIP_CONSDATA** consdata, /**< pointer to consdata */
1939 SCIP_VAR** vars, /**< array of integer variables */
1940 SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1941 int* durations, /**< array containing corresponding durations */
1942 int* demands, /**< array containing corresponding demands */
1943 int nvars, /**< number of variables */
1944 int capacity, /**< available cumulative capacity */
1945 int hmin, /**< left bound of time axis to be considered (including hmin) */
1946 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1947 SCIP_Bool check /**< is the corresponding constraint a check constraint */
1948 )
1949{
1950 int v;
1951
1952 assert(scip != NULL);
1953 assert(consdata != NULL);
1954 assert(vars != NULL || nvars > 0);
1955 assert(demands != NULL);
1956 assert(durations != NULL);
1957 assert(capacity >= 0);
1958 assert(hmin >= 0);
1959 assert(hmin < hmax);
1960
1961 /* create constraint data */
1962 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1963
1964 (*consdata)->hmin = hmin;
1965 (*consdata)->hmax = hmax;
1966
1967 (*consdata)->capacity = capacity;
1968 (*consdata)->demandrows = NULL;
1969 (*consdata)->demandrowssize = 0;
1970 (*consdata)->ndemandrows = 0;
1971 (*consdata)->scoverrows = NULL;
1972 (*consdata)->nscoverrows = 0;
1973 (*consdata)->scoverrowssize = 0;
1974 (*consdata)->bcoverrows = NULL;
1975 (*consdata)->nbcoverrows = 0;
1976 (*consdata)->bcoverrowssize = 0;
1977 (*consdata)->nvars = nvars;
1978 (*consdata)->varssize = nvars;
1979 (*consdata)->signature = 0;
1980 (*consdata)->validsignature = FALSE;
1981 (*consdata)->normalized = FALSE;
1982 (*consdata)->covercuts = FALSE;
1983 (*consdata)->propagated = FALSE;
1984 (*consdata)->varbounds = FALSE;
1985 (*consdata)->triedsolving = FALSE;
1986
1987 if( nvars > 0 )
1988 {
1989 assert(vars != NULL); /* for flexelint */
1990
1991 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1992 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1993 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1994 (*consdata)->linkingconss = NULL;
1995
1996 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1997 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1998
1999 /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
2000 initializeLocks(*consdata, check);
2001
2002 if( linkingconss != NULL )
2003 {
2004 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
2005 }
2006
2007 /* transform variables, if they are not yet transformed */
2008 if( SCIPisTransformed(scip) )
2009 {
2010 SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
2011
2012 /* get transformed variables and do NOT captures these */
2013 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
2014
2015 /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
2016 * been multi-aggregated
2017 */
2018 for( v = 0; v < nvars; ++v )
2019 {
2020 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
2021 }
2022
2023 if( linkingconss != NULL )
2024 {
2025 /* get transformed constraints and captures these */
2026 SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
2027
2028 for( v = 0; v < nvars; ++v )
2029 assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
2030 }
2031 }
2032
2033#ifndef NDEBUG
2034 /* only binary and integer variables can be used in cumulative constraints
2035 * for fractional variable values, the constraint cannot be checked
2036 */
2037 for( v = 0; v < (*consdata)->nvars; ++v )
2038 assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
2039#endif
2040 }
2041 else
2042 {
2043 (*consdata)->vars = NULL;
2044 (*consdata)->downlocks = NULL;
2045 (*consdata)->uplocks = NULL;
2046 (*consdata)->demands = NULL;
2047 (*consdata)->durations = NULL;
2048 (*consdata)->linkingconss = NULL;
2049 }
2050
2051 /* initialize values for running propagation algorithms efficiently */
2052 (*consdata)->resstrength1 = -1.0;
2053 (*consdata)->resstrength2 = -1.0;
2054 (*consdata)->cumfactor1 = -1.0;
2055 (*consdata)->disjfactor1 = -1.0;
2056 (*consdata)->disjfactor2 = -1.0;
2057 (*consdata)->estimatedstrength = -1.0;
2058
2059 SCIPstatistic( (*consdata)->maxpeak = -1 );
2060
2061 return SCIP_OKAY;
2062}
2063
2064/** releases LP rows of constraint data and frees rows array */
2065static
2067 SCIP* scip, /**< SCIP data structure */
2068 SCIP_CONSDATA** consdata /**< constraint data */
2069 )
2070{
2071 int r;
2072
2073 assert(consdata != NULL);
2074 assert(*consdata != NULL);
2075
2076 for( r = 0; r < (*consdata)->ndemandrows; ++r )
2077 {
2078 assert((*consdata)->demandrows[r] != NULL);
2079 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2080 }
2081
2082 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2083
2084 (*consdata)->ndemandrows = 0;
2085 (*consdata)->demandrowssize = 0;
2086
2087 /* free rows of cover cuts */
2088 for( r = 0; r < (*consdata)->nscoverrows; ++r )
2089 {
2090 assert((*consdata)->scoverrows[r] != NULL);
2091 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2092 }
2093
2094 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2095
2096 (*consdata)->nscoverrows = 0;
2097 (*consdata)->scoverrowssize = 0;
2098
2099 for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2100 {
2101 assert((*consdata)->bcoverrows[r] != NULL);
2102 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2103 }
2104
2105 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2106
2107 (*consdata)->nbcoverrows = 0;
2108 (*consdata)->bcoverrowssize = 0;
2109
2110 (*consdata)->covercuts = FALSE;
2111
2112 return SCIP_OKAY;
2113}
2114
2115/** frees a cumulative constraint data */
2116static
2118 SCIP* scip, /**< SCIP data structure */
2119 SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2120 )
2121{
2122 int varssize;
2123 int nvars;
2124
2125 assert(consdata != NULL);
2126 assert(*consdata != NULL);
2127
2128 nvars = (*consdata)->nvars;
2129 varssize = (*consdata)->varssize;
2130
2131 if( varssize > 0 )
2132 {
2133 int v;
2134
2135 /* release and free the rows */
2136 SCIP_CALL( consdataFreeRows(scip, consdata) );
2137
2138 /* release the linking constraints if they were generated */
2139 if( (*consdata)->linkingconss != NULL )
2140 {
2141 for( v = nvars-1; v >= 0; --v )
2142 {
2143 assert((*consdata)->linkingconss[v] != NULL );
2144 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2145 }
2146
2147 SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2148 }
2149
2150 /* free arrays */
2151 SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2152 SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2153 SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2154 SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2155 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2156 }
2157
2158 /* free memory */
2159 SCIPfreeBlockMemory(scip, consdata);
2160
2161 return SCIP_OKAY;
2162}
2163
2164/** prints cumulative constraint to file stream */
2165static
2167 SCIP* scip, /**< SCIP data structure */
2168 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2169 FILE* file /**< output file (or NULL for standard output) */
2170 )
2171{
2172 int v;
2173
2174 assert(consdata != NULL);
2175
2176 /* print coefficients */
2177 SCIPinfoMessage( scip, file, "cumulative(");
2178
2179 for( v = 0; v < consdata->nvars; ++v )
2180 {
2181 assert(consdata->vars[v] != NULL);
2182 if( v > 0 )
2183 SCIPinfoMessage(scip, file, ", ");
2184 SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2185 SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2186 consdata->durations[v], consdata->demands[v]);
2187 }
2188 SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2189}
2190
2191/** deletes coefficient at given position from constraint data */
2192static
2194 SCIP* scip, /**< SCIP data structure */
2195 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2196 SCIP_CONS* cons, /**< knapsack constraint */
2197 int pos /**< position of coefficient to delete */
2198 )
2199{
2200 SCIP_CONSHDLR* conshdlr;
2201 SCIP_CONSHDLRDATA* conshdlrdata;
2202
2203 assert(scip != NULL);
2204 assert(consdata != NULL);
2205 assert(cons != NULL);
2206 assert(SCIPconsIsTransformed(cons));
2207 assert(!SCIPinProbing(scip));
2208
2209 SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2210 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2211
2212 /* remove the rounding locks for the deleted variable */
2213 SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2214
2215 consdata->downlocks[pos] = FALSE;
2216 consdata->uplocks[pos] = FALSE;
2217
2218 if( consdata->linkingconss != NULL )
2219 {
2220 SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2221 }
2222
2223 /* get event handler */
2224 conshdlr = SCIPconsGetHdlr(cons);
2225 assert(conshdlr != NULL);
2226 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2227 assert(conshdlrdata != NULL);
2228 assert(conshdlrdata->eventhdlr != NULL);
2229
2230 /* drop events */
2231 SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2232
2233 SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2234 SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2235
2236 /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2237 * position
2238 */
2239 if( pos != consdata->nvars - 1 )
2240 {
2241 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2242 consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2243 consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2244 consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2245 consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2246
2247 if( consdata->linkingconss != NULL )
2248 {
2249 consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2250 }
2251 }
2252
2253 consdata->nvars--;
2254 consdata->validsignature = FALSE;
2255 consdata->normalized = FALSE;
2256
2257 return SCIP_OKAY;
2258}
2259
2260/** collect linking constraints for each integer variable */
2261static
2263 SCIP* scip, /**< SCIP data structure */
2264 SCIP_CONSDATA* consdata /**< pointer to consdata */
2265 )
2266{
2267 int nvars;
2268 int v;
2269
2270 assert(scip != NULL);
2271 assert(consdata != NULL);
2272
2273 nvars = consdata->nvars;
2274 assert(nvars > 0);
2275 assert(consdata->linkingconss == NULL);
2276
2277 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2278
2279 for( v = 0; v < nvars; ++v )
2280 {
2281 SCIP_CONS* cons;
2282 SCIP_VAR* var;
2283
2284 var = consdata->vars[v];
2285 assert(var != NULL);
2286
2287 SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2288
2289 /* create linking constraint if it does not exist yet */
2290 if( !SCIPexistsConsLinking(scip, var) )
2291 {
2292 char name[SCIP_MAXSTRLEN];
2293
2294 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2295
2296 /* creates and captures an linking constraint */
2297 SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2298 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2299 SCIP_CALL( SCIPaddCons(scip, cons) );
2300 consdata->linkingconss[v] = cons;
2301 }
2302 else
2303 {
2304 consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2305 SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2306 }
2307
2308 assert(SCIPexistsConsLinking(scip, var));
2309 assert(consdata->linkingconss[v] != NULL);
2310 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2311 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2312 }
2313
2314 return SCIP_OKAY;
2315}
2316
2317/**@} */
2318
2319
2320/**@name Check methods
2321 *
2322 * @{
2323 */
2324
2325/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2326 * given solution is satisfied
2327 */
2328static
2330 SCIP* scip, /**< SCIP data structure */
2331 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2332 int nvars, /**< number of variables (jobs) */
2333 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2334 int* durations, /**< array containing corresponding durations */
2335 int* demands, /**< array containing corresponding demands */
2336 int capacity, /**< available cumulative capacity */
2337 int hmin, /**< left bound of time axis to be considered (including hmin) */
2338 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2339 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2340 SCIP_CONS* cons, /**< constraint which is checked */
2341 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2342 )
2343{
2344 int* startsolvalues; /* stores when each job is starting */
2345 int* endsolvalues; /* stores when each job ends */
2346 int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2347 int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2348
2349 int freecapacity;
2350 int curtime; /* point in time which we are just checking */
2351 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2352 int j;
2353
2354 SCIP_Real absviol;
2355 SCIP_Real relviol;
2356
2357 assert(scip != NULL);
2358 assert(violated != NULL);
2359
2360 (*violated) = FALSE;
2361
2362 if( nvars == 0 )
2363 return SCIP_OKAY;
2364
2365 assert(vars != NULL);
2366 assert(demands != NULL);
2367 assert(durations != NULL);
2368
2369 /* compute time points where we have to check whether capacity constraint is infeasible or not */
2370 SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2371 SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2372 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2373 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2374
2375 /* assign variables, start and endpoints to arrays */
2376 for ( j = 0; j < nvars; ++j )
2377 {
2378 int solvalue;
2379
2380 /* the constraint of the cumulative constraint handler should be called after the integrality check */
2381 assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2382
2383 solvalue = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2384
2385 /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2386 * jobs which start before hmin to hmin
2387 */
2388 startsolvalues[j] = MAX(solvalue, hmin);
2389 startindices[j] = j;
2390
2391 endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2392 endindices[j] = j;
2393 }
2394
2395 /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2396 * corresponding indices in the same way)
2397 */
2398 SCIPsortIntInt(startsolvalues, startindices, nvars);
2399 SCIPsortIntInt(endsolvalues, endindices, nvars);
2400
2401 endindex = 0;
2402 freecapacity = capacity;
2403 absviol = 0.0;
2404 relviol = 0.0;
2405
2406 /* check each start point of a job whether the capacity is kept or not */
2407 for( j = 0; j < nvars; ++j )
2408 {
2409 /* only check intervals [hmin,hmax) */
2410 curtime = startsolvalues[j];
2411
2412 if( curtime >= hmax )
2413 break;
2414
2415 /* subtract all capacity needed up to this point */
2416 freecapacity -= demands[startindices[j]];
2417 while( j+1 < nvars && startsolvalues[j+1] == curtime )
2418 {
2419 j++;
2420 freecapacity -= demands[startindices[j]];
2421 }
2422
2423 /* free all capacity usages of jobs that are no longer running */
2424 while( endindex < nvars && curtime >= endsolvalues[endindex] )
2425 {
2426 freecapacity += demands[endindices[endindex]];
2427 ++endindex;
2428 }
2429 assert(freecapacity <= capacity);
2430
2431 /* update absolute and relative violation */
2432 if( absviol < (SCIP_Real) (-freecapacity) )
2433 {
2434 absviol = -freecapacity;
2435 relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2436 }
2437
2438 /* check freecapacity to be smaller than zero */
2439 if( freecapacity < 0 && curtime >= hmin )
2440 {
2441 SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2442 (*violated) = TRUE;
2443
2444 if( printreason )
2445 {
2446 int i;
2447
2448 /* first state the violated constraints */
2449 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2450
2451 /* second state the reason */
2453 ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2454 curtime, capacity, capacity - freecapacity);
2455
2456 for( i = 0; i <= j; ++i )
2457 {
2458 if( startsolvalues[i] + durations[startindices[i]] > curtime )
2459 {
2460 SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2461 SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2462 demands[startindices[i]]);
2463 }
2464 }
2465 }
2466 break;
2467 }
2468 } /*lint --e{850}*/
2469
2470 /* update constraint violation in solution */
2471 if( sol != NULL )
2472 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2473
2474 /* free all buffer arrays */
2475 SCIPfreeBufferArray(scip, &endindices);
2476 SCIPfreeBufferArray(scip, &startindices);
2477 SCIPfreeBufferArray(scip, &endsolvalues);
2478 SCIPfreeBufferArray(scip, &startsolvalues);
2479
2480 return SCIP_OKAY;
2481}
2482
2483/** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2484 * least zero or not. If not (*violated) is set to TRUE
2485 */
2486static
2488 SCIP* scip, /**< SCIP data structure */
2489 SCIP_CONS* cons, /**< constraint to be checked */
2490 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2491 SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2492 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2493 )
2494{
2495 SCIP_CONSDATA* consdata;
2496
2497 assert(scip != NULL);
2498 assert(cons != NULL);
2499 assert(violated != NULL);
2500
2501 SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2502
2503 consdata = SCIPconsGetData(cons);
2504 assert(consdata != NULL);
2505
2506 /* check the cumulative condition */
2507 SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2508 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2509 violated, cons, printreason) );
2510
2511 return SCIP_OKAY;
2512}
2513
2514/**@} */
2515
2516/**@name Conflict analysis
2517 *
2518 * @{
2519 */
2520
2521/** resolves the propagation of the core time algorithm */
2522static
2524 SCIP* scip, /**< SCIP data structure */
2525 int nvars, /**< number of start time variables (activities) */
2526 SCIP_VAR** vars, /**< array of start time variables */
2527 int* durations, /**< array of durations */
2528 int* demands, /**< array of demands */
2529 int capacity, /**< cumulative capacity */
2530 int hmin, /**< left bound of time axis to be considered (including hmin) */
2531 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2532 SCIP_VAR* infervar, /**< inference variable */
2533 int inferdemand, /**< demand of the inference variable */
2534 int inferpeak, /**< time point which causes the propagation */
2535 int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2536 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2537 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2538 int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2539 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2540 )
2541{
2542 SCIP_VAR* var;
2543 SCIP_Bool* reported;
2544 int duration;
2545 int maxlst;
2546 int minect;
2547 int ect;
2548 int lst;
2549 int j;
2550
2552
2553 SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2554 SCIPvarGetName(infervar), inferdemand, inferpeak);
2555 assert(nvars > 0);
2556
2557 /* adjusted capacity */
2558 capacity -= inferdemand;
2559 maxlst = INT_MIN;
2560 minect = INT_MAX;
2561
2562 SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2563 BMSclearMemoryArray(reported, nvars);
2564
2565 /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2566 * inference peak and those where the current conflict bounds provide a core at the inference peak
2567 */
2568 for( j = 0; j < nvars && capacity >= 0; ++j )
2569 {
2570 var = vars[j];
2571 assert(var != NULL);
2572
2573 /* skip inference variable */
2574 if( var == infervar )
2575 continue;
2576
2577 duration = durations[j];
2578 assert(duration > 0);
2579
2580 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2581 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2582 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2583 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2584 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2585
2586 SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2588 SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2589
2590 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2592
2593 /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2594 * that job without adding it the explanation
2595 */
2596 if( inferpeak < ect && lst <= inferpeak )
2597 {
2598 capacity -= demands[j];
2599 reported[j] = TRUE;
2600
2601 maxlst = MAX(maxlst, lst);
2602 minect = MIN(minect, ect);
2603 assert(maxlst < minect);
2604
2605 if( explanation != NULL )
2606 explanation[j] = TRUE;
2607
2608 continue;
2609 }
2610
2611 /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2612 * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2613 * not part of the conflict yet we get the global bounds back.
2614 */
2615 ect = boundedConvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2617
2618 /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2619 * of that job without and collect the job as part of the explanation
2620 *
2621 * @note we do not need to reported that job to SCIP since the required bounds are already reported
2622 */
2623 if( inferpeak < ect && lst <= inferpeak )
2624 {
2625 capacity -= demands[j];
2626 reported[j] = TRUE;
2627
2628 maxlst = MAX(maxlst, lst);
2629 minect = MIN(minect, ect);
2630 assert(maxlst < minect);
2631
2632 if( explanation != NULL )
2633 explanation[j] = TRUE;
2634 }
2635 }
2636
2637 if( capacity >= 0 )
2638 {
2639 int* cands;
2640 int* canddemands;
2641 int ncands;
2642 int c;
2643
2644 SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2645 SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2646 ncands = 0;
2647
2648 /* collect all cores of the variables which lay in the considered time window except the inference variable */
2649 for( j = 0; j < nvars; ++j )
2650 {
2651 var = vars[j];
2652 assert(var != NULL);
2653
2654 /* skip inference variable */
2655 if( var == infervar || reported[j] )
2656 continue;
2657
2658 duration = durations[j];
2659 assert(duration > 0);
2660
2661 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2662 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2663 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2664 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2665 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2666
2667 /* collect local core information */
2668 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2670
2671 SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2672 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2673 SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2674
2675 /* check if the inference peak is part of the core */
2676 if( inferpeak < ect && lst <= inferpeak )
2677 {
2678 cands[ncands] = j;
2679 canddemands[ncands] = demands[j];
2680 ncands++;
2681
2682 capacity -= demands[j];
2683 }
2684 }
2685
2686 /* sort candidates indices w.r.t. their demands */
2687 SCIPsortDownIntInt(canddemands, cands, ncands);
2688
2689 assert(capacity < 0);
2690 assert(ncands > 0);
2691
2692 /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2693 while( capacity + canddemands[ncands-1] < 0 )
2694 {
2695 ncands--;
2696 capacity += canddemands[ncands];
2697 assert(ncands > 0);
2698 }
2699
2700 /* compute the size (number of time steps) of the job cores */
2701 for( c = 0; c < ncands; ++c )
2702 {
2703 var = vars[cands[c]];
2704 assert(var != NULL);
2705
2706 duration = durations[cands[c]];
2707
2708 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2710
2711 maxlst = MAX(maxlst, lst);
2712 minect = MIN(minect, ect);
2713 assert(maxlst < minect);
2714 }
2715
2716 SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2717 assert(inferpeak >= maxlst);
2718 assert(inferpeak < minect);
2719
2720 /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2721 if( relaxedpeak < inferpeak )
2722 {
2723 inferpeak = MAX(maxlst, relaxedpeak);
2724 }
2725 else if( relaxedpeak > inferpeak )
2726 {
2727 inferpeak = MIN(minect-1, relaxedpeak);
2728 }
2729 assert(inferpeak >= hmin);
2730 assert(inferpeak < hmax);
2731 assert(inferpeak >= maxlst);
2732 assert(inferpeak < minect);
2733
2734 /* post all necessary bound changes */
2735 for( c = 0; c < ncands; ++c )
2736 {
2737 var = vars[cands[c]];
2738 assert(var != NULL);
2739
2740 if( usebdwidening )
2741 {
2742 duration = durations[cands[c]];
2743
2744 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2745 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2746 }
2747 else
2748 {
2749 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2750 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2751 }
2752
2753 if( explanation != NULL )
2754 explanation[cands[c]] = TRUE;
2755 }
2756
2757 SCIPfreeBufferArray(scip, &canddemands);
2758 SCIPfreeBufferArray(scip, &cands);
2759 }
2760
2761 SCIPfreeBufferArray(scip, &reported);
2762
2763 if( provedpeak != NULL )
2764 *provedpeak = inferpeak;
2765
2766 return SCIP_OKAY;
2767}
2768
2769/** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2770static
2772 int begin, /**< begin of the times interval */
2773 int end, /**< end of time interval */
2774 int est, /**< earliest start time */
2775 int lst, /**< latest start time */
2776 int duration /**< duration of the job */
2777 )
2778{
2779 int left;
2780 int right;
2781 int ect;
2782 int lct;
2783
2784 ect = est + duration;
2785 lct = lst + duration;
2786
2787 /* check if job runs completely within [begin,end) */
2788 if( lct <= end && est >= begin )
2789 return duration;
2790
2791 assert(lst <= end && ect >= begin);
2792
2793 left = ect - begin;
2794 assert(left > 0);
2795
2796 right = end - lst;
2797 assert(right > 0);
2798
2799 return MIN3(left, right, end - begin);
2800}
2801
2802/** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2803 * reason
2804 *
2805 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2806 */
2807static
2809 SCIP* scip, /**< SCIP data structure */
2810 int nvars, /**< number of start time variables (activities) */
2811 SCIP_VAR** vars, /**< array of start time variables */
2812 int* durations, /**< array of durations */
2813 int* demands, /**< array of demands */
2814 int capacity, /**< capacity of the cumulative condition */
2815 int begin, /**< begin of the time window */
2816 int end, /**< end of the time window */
2817 SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2818 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2819 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2820 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2821 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2822 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2823 )
2824{
2825 int* locenergies;
2826 int* overlaps;
2827 int* idxs;
2828
2829 SCIP_Longint requiredenergy;
2830 int v;
2831
2832 SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2833 SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2834 SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2835
2836 /* energy which needs be explained */
2837 requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2838
2839 SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2840
2841 /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2842 * takes
2843 */
2844 for( v = 0; v < nvars; ++v )
2845 {
2846 SCIP_VAR* var;
2847 int glbenergy;
2848 int duration;
2849 int demand;
2850 int est;
2851 int lst;
2852
2853 var = vars[v];
2854 assert(var != NULL);
2855
2856 locenergies[v] = 0;
2857 overlaps[v] = 0;
2858 idxs[v] = v;
2859
2860 demand = demands[v];
2861 assert(demand > 0);
2862
2863 duration = durations[v];
2864 assert(duration > 0);
2865
2866 /* check if the variable equals the inference variable (the one which was propagated) */
2867 if( infervar == var )
2868 {
2869 int overlap;
2870 int right;
2871 int left;
2872
2873 assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2874
2875 SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2876 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2877 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2878
2879 /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2880 * which is necessary from the inference variable
2881 */
2882 if( boundtype == SCIP_BOUNDTYPE_UPPER )
2883 {
2884 int lct;
2885
2886 /* get the latest start time of the infer start time variable before the propagation took place */
2888
2889 /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2890 * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2891 * scheduled w.r.t. its latest start time
2892 */
2893 assert(lst < end);
2894
2895 /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2896 * interval (before the propagation)
2897 */
2898 right = MIN3(end - lst, end - begin, duration);
2899
2900 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2901 assert(right > 0);
2902
2903 lct = boundedConvertRealToInt(scip, relaxedbd) + duration;
2904 assert(begin <= lct);
2905 assert(bdchgidx == NULL ||
2906 boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2907
2908 /* compute the overlap of the job after the propagation but considering the relaxed bound */
2909 left = MIN(lct - begin + 1, end - begin);
2910 assert(left > 0);
2911
2912 /* compute the minimum overlap; */
2913 overlap = MIN(left, right);
2914 assert(overlap > 0);
2915 assert(overlap <= end - begin);
2916 assert(overlap <= duration);
2917
2918 if( usebdwidening )
2919 {
2920 assert(boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2921 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2922 }
2923 else
2924 {
2925 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2926 }
2927 }
2928 else
2929 {
2930 int ect;
2931
2932 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2933
2934 /* get the earliest completion time of the infer start time variable before the propagation took place */
2935 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2936
2937 /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2938 * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2939 * the job is scheduled w.r.t. its earliest start time
2940 */
2941 assert(ect > begin);
2942
2943 /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2944 * interval (before the propagation)
2945 */
2946 left = MIN3(ect - begin, end - begin, duration);
2947
2948 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2949 assert(left > 0);
2950
2951 est = boundedConvertRealToInt(scip, relaxedbd);
2952 assert(end >= est);
2953 assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
2954
2955 /* compute the overlap of the job after the propagation but considering the relaxed bound */
2956 right = MIN(end - est + 1, end - begin);
2957 assert(right > 0);
2958
2959 /* compute the minimum overlap */
2960 overlap = MIN(left, right);
2961 assert(overlap > 0);
2962 assert(overlap <= end - begin);
2963 assert(overlap <= duration);
2964
2965 if( usebdwidening )
2966 {
2967 assert(boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
2968 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
2969 }
2970 else
2971 {
2972 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2973 }
2974 }
2975
2976 /* subtract the amount of energy which is available due to the overlap of the inference start time */
2977 requiredenergy -= (SCIP_Longint) overlap * demand;
2978
2979 if( explanation != NULL )
2980 explanation[v] = TRUE;
2981
2982 continue;
2983 }
2984
2985 /* global time points */
2988
2989 glbenergy = 0;
2990
2991 /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
2992 * time window
2993 */
2994 if( est + duration > begin && lst < end )
2995 {
2996 /* evaluated global contribution */
2997 glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
2998
2999 /* remove the globally available energy form the required energy */
3000 requiredenergy -= glbenergy;
3001
3002 if( explanation != NULL )
3003 explanation[v] = TRUE;
3004 }
3005
3006 /* local time points */
3009
3010 /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3011 * time window
3012 */
3013 if( est + duration > begin && lst < end )
3014 {
3015 overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3016
3017 /* evaluated additionally local energy contribution */
3018 locenergies[v] = overlaps[v] * demand - glbenergy;
3019 assert(locenergies[v] >= 0);
3020 }
3021 }
3022
3023 /* sort the variable contributions w.r.t. additional local energy contributions */
3024 SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3025
3026 /* add local energy contributions until an overload is implied */
3027 for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3028 {
3029 SCIP_VAR* var;
3030 int duration;
3031 int overlap;
3032 int relaxlb;
3033 int relaxub;
3034 int idx;
3035
3036 idx = idxs[v];
3037 assert(idx >= 0 && idx < nvars);
3038
3039 var = vars[idx];
3040 assert(var != NULL);
3041 assert(var != infervar);
3042
3043 duration = durations[idx];
3044 assert(duration > 0);
3045
3046 overlap = overlaps[v];
3047 assert(overlap > 0);
3048
3049 requiredenergy -= locenergies[v];
3050
3051 if( requiredenergy < -1 )
3052 {
3053 int demand;
3054
3055 demand = demands[idx];
3056 assert(demand > 0);
3057
3058 overlap += (int)((requiredenergy + 1) / demand);
3059
3060#ifndef NDEBUG
3061 requiredenergy += locenergies[v];
3062 requiredenergy -= (SCIP_Longint) overlap * demand;
3063 assert(requiredenergy < 0);
3064#endif
3065 }
3066 assert(overlap > 0);
3067
3068 relaxlb = begin - duration + overlap;
3069 relaxub = end - overlap;
3070
3071 SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3072 SCIPvarGetName(var),
3076 relaxlb, relaxub, demands[idx], duration);
3077
3078 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3079 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3080
3081 if( explanation != NULL )
3082 explanation[idx] = TRUE;
3083 }
3084
3085 assert(requiredenergy < 0);
3086
3087 SCIPfreeBufferArray(scip, &idxs);
3088 SCIPfreeBufferArray(scip, &overlaps);
3089 SCIPfreeBufferArray(scip, &locenergies);
3090
3091 return SCIP_OKAY;
3092}
3093
3094/** resolve propagation w.r.t. the cumulative condition */
3095static
3097 SCIP* scip, /**< SCIP data structure */
3098 int nvars, /**< number of start time variables (activities) */
3099 SCIP_VAR** vars, /**< array of start time variables */
3100 int* durations, /**< array of durations */
3101 int* demands, /**< array of demands */
3102 int capacity, /**< cumulative capacity */
3103 int hmin, /**< left bound of time axis to be considered (including hmin) */
3104 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3105 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3106 INFERINFO inferinfo, /**< the user information */
3107 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3108 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3109 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3110 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3111 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3112 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3113 )
3114{
3115 switch( inferInfoGetProprule(inferinfo) )
3116 {
3118 {
3119 int inferdemand;
3120 int inferduration;
3121 int inferpos;
3122 int inferpeak;
3123 int relaxedpeak;
3124 int provedpeak;
3125
3126 /* get the position of the inferred variable in the vars array */
3127 inferpos = inferInfoGetData1(inferinfo);
3128 if( inferpos >= nvars || vars[inferpos] != infervar )
3129 {
3130 /* find inference variable in constraint */
3131 for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3132 {}
3133 }
3134 assert(inferpos < nvars);
3135 assert(vars[inferpos] == infervar);
3136
3137 inferdemand = demands[inferpos];
3138 inferduration = durations[inferpos];
3139
3140 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3141 {
3142 /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3143 * the inference variable
3144 */
3145 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3146
3147 SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3148 SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3149 SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3150
3151 /* get the inference peak that the time point which lead to the that propagtion */
3152 inferpeak = inferInfoGetData2(inferinfo);
3153 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3154 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3155 */
3156 assert(
3157 boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3158 relaxedpeak = boundedConvertRealToInt(scip, relaxedbd) + inferduration;
3159
3160 /* make sure that the relaxed peak is part of the effective horizon */
3161 relaxedpeak = MIN(relaxedpeak, hmax-1);
3162
3163 /* make sure that relaxed peak is not larger than the infer peak
3164 *
3165 * This can happen in case the variable is not an active variable!
3166 */
3167 relaxedpeak = MAX(relaxedpeak, inferpeak);
3168 assert(relaxedpeak >= inferpeak);
3169 assert(relaxedpeak >= hmin);
3170 }
3171 else
3172 {
3173 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3174
3175 SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3176 SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3177 SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3178
3179 /* get the time interval where the job could not be scheduled */
3180 inferpeak = inferInfoGetData2(inferinfo);
3181 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3182 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3183 */
3184 assert(boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3185 relaxedpeak = boundedConvertRealToInt(scip, relaxedbd) - 1;
3186
3187 /* make sure that the relaxed peak is part of the effective horizon */
3188 relaxedpeak = MAX(relaxedpeak, hmin);
3189
3190 /* make sure that relaxed peak is not larger than the infer peak
3191 *
3192 * This can happen in case the variable is not an active variable!
3193 */
3194 relaxedpeak = MIN(relaxedpeak, inferpeak);
3195 assert(relaxedpeak < hmax);
3196 }
3197
3198 /* resolves the propagation of the core time algorithm */
3199 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3200 infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3201
3202 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3203 {
3204 if( usebdwidening )
3205 {
3206 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3207 }
3208 else
3209 {
3210 /* old upper bound of variable itself is part of the explanation */
3211 SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3212 }
3213 }
3214 else
3215 {
3216 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3217
3218 if( usebdwidening )
3219 {
3220 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3221 }
3222 else
3223 {
3224 /* old lower bound of variable itself is part of the explanation */
3225 SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3226 }
3227 }
3228
3229 if( explanation != NULL )
3230 explanation[inferpos] = TRUE;
3231
3232 break;
3233 }
3235 case PROPRULE_3_TTEF:
3236 {
3237 int begin;
3238 int end;
3239
3240 begin = inferInfoGetData1(inferinfo);
3241 end = inferInfoGetData2(inferinfo);
3242 assert(begin < end);
3243
3244 begin = MAX(begin, hmin);
3245 end = MIN(end, hmax);
3246
3247 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3248 begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3249
3250 break;
3251 }
3252
3253 case PROPRULE_0_INVALID:
3254 default:
3255 SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3256 SCIPABORT();
3257 return SCIP_INVALIDDATA; /*lint !e527*/
3258 }
3259
3260 (*result) = SCIP_SUCCESS;
3261
3262 return SCIP_OKAY;
3263}
3264
3265/**@} */
3266
3267
3268/**@name Enforcement methods
3269 *
3270 * @{
3271 */
3272
3273/** apply all fixings which are given by the alternative bounds */
3274static
3276 SCIP* scip, /**< SCIP data structure */
3277 SCIP_VAR** vars, /**< array of active variables */
3278 int nvars, /**< number of active variables */
3279 int* alternativelbs, /**< alternative lower bounds */
3280 int* alternativeubs, /**< alternative lower bounds */
3281 int* downlocks, /**< number of constraints with down lock participating by the computation */
3282 int* uplocks, /**< number of constraints with up lock participating by the computation */
3283 SCIP_Bool* branched /**< pointer to store if a branching was applied */
3284 )
3285{
3286 int v;
3287
3288 for( v = 0; v < nvars; ++v )
3289 {
3290 SCIP_VAR* var;
3291 SCIP_Real objval;
3292
3293 var = vars[v];
3294 assert(var != NULL);
3295
3296 objval = SCIPvarGetObj(var);
3297
3298 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3299 {
3300 int ub;
3301
3303
3304 if( alternativelbs[v] <= ub )
3305 {
3306 SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3307 (*branched) = TRUE;
3308
3309 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3310 SCIPvarGetLbLocal(var), alternativelbs[v]);
3311
3312 return SCIP_OKAY;
3313 }
3314 }
3315
3316 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3317 {
3318 int lb;
3319
3321
3322 if( alternativeubs[v] >= lb )
3323 {
3324 SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3325 (*branched) = TRUE;
3326
3327 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3328 alternativeubs[v], SCIPvarGetUbLocal(var));
3329
3330 return SCIP_OKAY;
3331 }
3332 }
3333 }
3334
3335 return SCIP_OKAY;
3336}
3337
3338/** remove the capacity requirments for all job which start at the curtime */
3339static
3341 SCIP_CONSDATA* consdata, /**< constraint data */
3342 int curtime, /**< current point in time */
3343 int* starttimes, /**< array of start times */
3344 int* startindices, /**< permutation with respect to the start times */
3345 int* freecapacity, /**< pointer to store the resulting free capacity */
3346 int* idx, /**< pointer to index in start time array */
3347 int nvars /**< number of vars in array of starttimes and startindices */
3348 )
3349{
3350#if defined SCIP_DEBUG && !defined NDEBUG
3351 int oldidx;
3352
3353 assert(idx != NULL);
3354 oldidx = *idx;
3355#else
3356 assert(idx != NULL);
3357#endif
3358
3359 assert(starttimes != NULL);
3360 assert(starttimes != NULL);
3361 assert(freecapacity != NULL);
3362 assert(starttimes[*idx] == curtime);
3363 assert(consdata->demands != NULL);
3364 assert(freecapacity != idx);
3365
3366 /* subtract all capacity needed up to this point */
3367 (*freecapacity) -= consdata->demands[startindices[*idx]];
3368
3369 while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3370 {
3371 ++(*idx);
3372 (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3373 assert(freecapacity != idx);
3374 }
3375#ifdef SCIP_DEBUG
3376 assert(oldidx <= *idx);
3377#endif
3378}
3379
3380/** add the capacity requirments for all job which end at the curtime */
3381static
3383 SCIP_CONSDATA* consdata, /**< constraint data */
3384 int curtime, /**< current point in time */
3385 int* endtimes, /**< array of end times */
3386 int* endindices, /**< permutation with rspect to the end times */
3387 int* freecapacity, /**< pointer to store the resulting free capacity */
3388 int* idx, /**< pointer to index in end time array */
3389 int nvars /**< number of vars in array of starttimes and startindices */
3390 )
3391{
3392#if defined SCIP_DEBUG && !defined NDEBUG
3393 int oldidx;
3394 oldidx = *idx;
3395#endif
3396
3397 /* free all capacity usages of jobs the are no longer running */
3398 while( endtimes[*idx] <= curtime && *idx < nvars)
3399 {
3400 (*freecapacity) += consdata->demands[endindices[*idx]];
3401 ++(*idx);
3402 }
3403
3404#ifdef SCIP_DEBUG
3405 assert(oldidx <= *idx);
3406#endif
3407}
3408
3409/** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3410static
3412 SCIP* scip, /**< SCIP data structure */
3413 SCIP_CONSDATA* consdata, /**< constraint handler data */
3414 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3415 int* timepoint /**< pointer to store the time point of the peak */
3416 )
3417{
3418 int* starttimes; /* stores when each job is starting */
3419 int* endtimes; /* stores when each job ends */
3420 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3421 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3422
3423 int nvars; /* number of activities for this constraint */
3424 int freecapacity; /* remaining capacity */
3425 int curtime; /* point in time which we are just checking */
3426 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3427
3428 int hmin;
3429 int hmax;
3430
3431 int j;
3432
3433 assert(consdata != NULL);
3434
3435 nvars = consdata->nvars;
3436 assert(nvars > 0);
3437
3438 *timepoint = consdata->hmax;
3439
3440 assert(consdata->vars != NULL);
3441
3442 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3443 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3444 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3445 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3446
3447 /* create event point arrays */
3448 createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3449 starttimes, endtimes, startindices, endindices);
3450
3451 endindex = 0;
3452 freecapacity = consdata->capacity;
3453 hmin = consdata->hmin;
3454 hmax = consdata->hmax;
3455
3456 /* check each startpoint of a job whether the capacity is kept or not */
3457 for( j = 0; j < nvars; ++j )
3458 {
3459 curtime = starttimes[j];
3460 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3461
3462 if( curtime >= hmax )
3463 break;
3464
3465 /* remove the capacity requirments for all job which start at the curtime */
3466 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3467
3468 /* add the capacity requirments for all job which end at the curtime */
3469 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3470
3471 assert(freecapacity <= consdata->capacity);
3472 assert(endindex <= nvars);
3473
3474 /* endindex - points to the next job which will finish */
3475 /* j - points to the last job that has been released */
3476
3477 /* if free capacity is smaller than zero, then add branching candidates */
3478 if( freecapacity < 0 && curtime >= hmin )
3479 {
3480 *timepoint = curtime;
3481 break;
3482 }
3483 } /*lint --e{850}*/
3484
3485 /* free all buffer arrays */
3486 SCIPfreeBufferArray(scip, &endindices);
3487 SCIPfreeBufferArray(scip, &startindices);
3488 SCIPfreeBufferArray(scip, &endtimes);
3489 SCIPfreeBufferArray(scip, &starttimes);
3490
3491 return SCIP_OKAY;
3492}
3493
3494/** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3495static
3497 SCIP* scip, /**< SCIP data structure */
3498 SCIP_CONS** conss, /**< constraints to be processed */
3499 int nconss, /**< number of constraints */
3500 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3501 int* nbranchcands /**< pointer to store the number of branching variables */
3502 )
3503{
3504 SCIP_HASHTABLE* collectedvars;
3505 int c;
3506
3507 assert(scip != NULL);
3508 assert(conss != NULL);
3509
3510 /* create a hash table */
3512 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3513
3514 assert(scip != NULL);
3515 assert(conss != NULL);
3516
3517 for( c = 0; c < nconss; ++c )
3518 {
3519 SCIP_CONS* cons;
3520 SCIP_CONSDATA* consdata;
3521
3522 int curtime;
3523 int j;
3524
3525 cons = conss[c];
3526 assert(cons != NULL);
3527
3528 if( !SCIPconsIsActive(cons) )
3529 continue;
3530
3531 consdata = SCIPconsGetData(cons);
3532 assert(consdata != NULL);
3533
3534 /* get point in time when capacity is exceeded */
3535 SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3536
3537 if( curtime < consdata->hmin || curtime >= consdata->hmax )
3538 continue;
3539
3540 /* report all variables that are running at that point in time */
3541 for( j = 0; j < consdata->nvars; ++j )
3542 {
3543 SCIP_VAR* var;
3544 int lb;
3545 int ub;
3546
3547 var = consdata->vars[j];
3548 assert(var != NULL);
3549
3550 /* check if the variable was already added */
3551 if( SCIPhashtableExists(collectedvars, (void*)var) )
3552 continue;
3553
3556
3557 if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3558 {
3559 SCIP_Real solval;
3560 SCIP_Real score;
3561
3562 solval = SCIPgetSolVal(scip, sol, var);
3563 score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3564
3565 SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3566 SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3567 (*nbranchcands)++;
3568
3569 SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3570 }
3571 }
3572 }
3573
3574 SCIPhashtableFree(&collectedvars);
3575
3576 SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3577
3578 return SCIP_OKAY;
3579}
3580
3581/** enforcement of an LP, pseudo, or relaxation solution */
3582static
3584 SCIP* scip, /**< SCIP data structure */
3585 SCIP_CONS** conss, /**< constraints to be processed */
3586 int nconss, /**< number of constraints */
3587 SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3588 SCIP_Bool branch, /**< should branching candidates be collected */
3589 SCIP_RESULT* result /**< pointer to store the result */
3590 )
3591{
3592 if( branch )
3593 {
3594 int nbranchcands;
3595
3596 nbranchcands = 0;
3597 SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3598
3599 if( nbranchcands > 0 )
3600 (*result) = SCIP_INFEASIBLE;
3601 }
3602 else
3603 {
3604 SCIP_Bool violated;
3605 int c;
3606
3607 violated = FALSE;
3608
3609 /* first check if a constraints is violated */
3610 for( c = 0; c < nconss && !violated; ++c )
3611 {
3612 SCIP_CONS* cons;
3613
3614 cons = conss[c];
3615 assert(cons != NULL);
3616
3617 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3618 }
3619
3620 if( violated )
3621 (*result) = SCIP_INFEASIBLE;
3622 }
3623
3624 return SCIP_OKAY;
3625}
3626
3627/**@} */
3628
3629/**@name Propagation
3630 *
3631 * @{
3632 */
3633
3634/** check if cumulative constraint is independently of all other constraints */
3635static
3637 SCIP_CONS* cons /**< cumulative constraint */
3638 )
3639{
3640 SCIP_CONSDATA* consdata;
3641 SCIP_VAR** vars;
3642 SCIP_Bool* downlocks;
3643 SCIP_Bool* uplocks;
3644 int nvars;
3645 int v;
3646
3647 consdata = SCIPconsGetData(cons);
3648 assert(consdata != NULL);
3649
3650 nvars = consdata->nvars;
3651 vars = consdata->vars;
3652 downlocks = consdata->downlocks;
3653 uplocks = consdata->uplocks;
3654
3655 /* check if the cumulative constraint has the only locks on the involved variables */
3656 for( v = 0; v < nvars; ++v )
3657 {
3658 SCIP_VAR* var;
3659
3660 var = vars[v];
3661 assert(var != NULL);
3662
3663 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3664 || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3665 return FALSE;
3666 }
3667
3668 return TRUE;
3669}
3670
3671/** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3672 * (dual reductions)
3673 */
3674static
3676 SCIP* scip, /**< SCIP data structure */
3677 SCIP_CONS* cons, /**< cumulative constraint */
3678 SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3679 int* nchgbds, /**< pointer to store the number changed variable bounds */
3680 int* nfixedvars, /**< pointer to count number of fixings */
3681 int* ndelconss, /**< pointer to count number of deleted constraints */
3682 SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3683 SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3684 )
3685{
3686 SCIP_CONSDATA* consdata;
3687 SCIP_VAR** vars;
3688 SCIP_Real* objvals;
3689 SCIP_Real* lbs;
3690 SCIP_Real* ubs;
3691 SCIP_Real timelimit;
3692 SCIP_Real memorylimit;
3693 SCIP_Bool solved;
3694 SCIP_Bool error;
3695
3696 int ncheckconss;
3697 int nvars;
3698 int v;
3699
3700 assert(scip != NULL);
3701 assert(!SCIPconsIsModifiable(cons));
3702 assert(SCIPgetNConss(scip) > 0);
3703
3704 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3705 * would/could end in an implication which can lead to cutoff of the/all optimal solution
3706 */
3708 return SCIP_OKAY;
3709
3710 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3711 * use the locks to decide for a dual reduction using this constraint;
3712 */
3713 if( !SCIPconsIsChecked(cons) )
3714 return SCIP_OKAY;
3715
3716 ncheckconss = SCIPgetNCheckConss(scip);
3717
3718 /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3719 * presolved problem do nothing execpt to change the parameter settings
3720 */
3721 if( ncheckconss == 1 )
3722 {
3723 /* shrink the minimal maximum value for the conflict length */
3724 SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3725
3726 /* use only first unique implication point */
3727 SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3728
3729 /* do not use reconversion conflicts */
3730 SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3731
3732 /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3733 SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3734
3735 /* increase the number of conflicts which induce a restart */
3736 SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3737
3738 /* weight the variable which made into a conflict */
3739 SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3740
3741 /* do not check pseudo solution (for performance reasons) */
3742 SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3743
3744 /* use value based history to detect a reasonable branching point */
3745 SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3746
3747 /* turn of LP relaxation */
3748 SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3749
3750 /* prefer the down branch in case the value based history does not suggest something */
3751 SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3752
3753 /* accept any bound change */
3754 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3755
3756 /* allow for at most 10 restart, after that the value based history should be reliable */
3757 SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3758
3759 /* set priority for depth first search to highest possible value */
3760 SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3761
3762 return SCIP_OKAY;
3763 }
3764
3765 consdata = SCIPconsGetData(cons);
3766 assert(consdata != NULL);
3767
3768 /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3769 * fail on the first place
3770 */
3771 if( consdata->triedsolving )
3772 return SCIP_OKAY;
3773
3774 /* check if constraint is independently */
3775 if( !isConsIndependently(cons) )
3776 return SCIP_OKAY;
3777
3778 /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3779 * constraint is deleted; otherwise, we want to ensure that we do not try that again
3780 */
3781 consdata->triedsolving = TRUE;
3782
3783 SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3786
3787 nvars = consdata->nvars;
3788 vars = consdata->vars;
3789
3790 SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3791 SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3792 SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3793
3794 for( v = 0; v < nvars; ++v )
3795 {
3796 SCIP_VAR* var;
3797
3798 /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3799 * array
3800 */
3801 var = vars[v];
3802 assert(var != NULL);
3803
3804 lbs[v] = SCIPvarGetLbLocal(var);
3805 ubs[v] = SCIPvarGetUbLocal(var);
3806
3807 objvals[v] = SCIPvarGetObj(var);
3808 }
3809
3810 /* check whether there is enough time and memory left */
3811 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3812 if( !SCIPisInfinity(scip, timelimit) )
3813 timelimit -= SCIPgetSolvingTime(scip);
3814 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3815
3816 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3817 if( !SCIPisInfinity(scip, memorylimit) )
3818 {
3819 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3820 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3821 }
3822
3823 /* solve the cumulative condition separately */
3824 SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3825 consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3826
3827 if( !(*cutoff) && !(*unbounded) && !error )
3828 {
3829 SCIP_Bool infeasible;
3830 SCIP_Bool tightened;
3831 SCIP_Bool allfixed;
3832
3833 allfixed = TRUE;
3834
3835 for( v = 0; v < nvars; ++v )
3836 {
3837 /* check if variable is fixed */
3838 if( lbs[v] + 0.5 > ubs[v] )
3839 {
3840 SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3841 assert(!infeasible);
3842
3843 if( tightened )
3844 {
3845 (*nfixedvars)++;
3846 consdata->triedsolving = FALSE;
3847 }
3848 }
3849 else
3850 {
3851 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3852 assert(!infeasible);
3853
3854 if( tightened )
3855 {
3856 (*nchgbds)++;
3857 consdata->triedsolving = FALSE;
3858 }
3859
3860 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3861 assert(!infeasible);
3862
3863 if( tightened )
3864 {
3865 (*nchgbds)++;
3866 consdata->triedsolving = FALSE;
3867 }
3868
3869 allfixed = FALSE;
3870 }
3871 }
3872
3873 /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3874 if( allfixed )
3875 {
3877 (*ndelconss)++;
3878 }
3879 }
3880
3881 SCIPfreeBufferArray(scip, &objvals);
3884
3885 return SCIP_OKAY;
3886}
3887
3888/** start conflict analysis to analysis the core insertion which is infeasible */
3889static
3891 SCIP* scip, /**< SCIP data structure */
3892 int nvars, /**< number of start time variables (activities) */
3893 SCIP_VAR** vars, /**< array of start time variables */
3894 int* durations, /**< array of durations */
3895 int* demands, /**< array of demands */
3896 int capacity, /**< cumulative capacity */
3897 int hmin, /**< left bound of time axis to be considered (including hmin) */
3898 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3899 SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3900 int inferduration, /**< duration of the start time variable */
3901 int inferdemand, /**< demand of the start time variable */
3902 int inferpeak, /**< profile preak which causes the infeasibilty */
3903 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3904 SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3905 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3906 )
3907{
3908 SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3909 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3910 SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3911
3912 /* initialize conflict analysis if conflict analysis is applicable */
3914 {
3916
3917 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3918 infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3919
3920 SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3921
3922 /* add both bound of the inference variable since these biuld the core which we could not inserted */
3923 if( usebdwidening )
3924 {
3925 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3926 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3927 }
3928 else
3929 {
3930 SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3931 SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3932 }
3933
3934 *initialized = TRUE;
3935 }
3936
3937 return SCIP_OKAY;
3938}
3939
3940/** We are using the core resource profile which contains all core except the one of the start time variable which we
3941 * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3942 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3943 * analysis
3944 */
3945static
3947 SCIP* scip, /**< SCIP data structure */
3948 int nvars, /**< number of start time variables (activities) */
3949 SCIP_VAR** vars, /**< array of start time variables */
3950 int* durations, /**< array of durations */
3951 int* demands, /**< array of demands */
3952 int capacity, /**< cumulative capacity */
3953 int hmin, /**< left bound of time axis to be considered (including hmin) */
3954 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3955 SCIP_CONS* cons, /**< constraint which is propagated */
3956 SCIP_PROFILE* profile, /**< resource profile */
3957 int idx, /**< position of the variable to propagate */
3958 int* nchgbds, /**< pointer to store the number of bound changes */
3959 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3960 SCIP_Bool* initialized, /**< was conflict analysis initialized */
3961 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3962 SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
3963 )
3964{
3965 SCIP_VAR* var;
3966 int ntimepoints;
3967 int duration;
3968 int demand;
3969 int peak;
3970 int newlb;
3971 int est;
3972 int lst;
3973 int pos;
3974
3975 var = vars[idx];
3976 assert(var != NULL);
3977
3978 duration = durations[idx];
3979 assert(duration > 0);
3980
3981 demand = demands[idx];
3982 assert(demand > 0);
3983
3986 ntimepoints = SCIPprofileGetNTimepoints(profile);
3987
3988 /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
3989 * load which we have at the earliest start time (lower bound)
3990 */
3991 (void) SCIPprofileFindLeft(profile, est, &pos);
3992
3993 SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
3994
3995 /* we now trying to move the earliest start time in steps of at most "duration" length */
3996 do
3997 {
3998 INFERINFO inferinfo;
3999 SCIP_Bool tightened;
4000 int ect;
4001
4002#ifndef NDEBUG
4003 {
4004 /* in debug mode we check that we adjust the search position correctly */
4005 int tmppos;
4006
4007 (void)SCIPprofileFindLeft(profile, est, &tmppos);
4008 assert(pos == tmppos);
4009 }
4010#endif
4011 ect = est + duration;
4012 peak = -1;
4013
4014 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4015 * want a peak which is closest to the earliest completion time
4016 */
4017 do
4018 {
4019 /* check if the profile load conflicts with the demand of the start time variable */
4020 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4021 peak = pos;
4022
4023 pos++;
4024 }
4025 while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4026
4027 /* if we found no peak that means current the job could be scheduled at its earliest start time without
4028 * conflicting to the core resource profile
4029 */
4030 /* coverity[check_after_sink] */
4031 if( peak == -1 )
4032 break;
4033
4034 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4035 * profile. That means we have to move it to the next time point in the resource profile but at most to the
4036 * earliest completion time (the remaining move will done in the next loop)
4037 */
4038 newlb = SCIPprofileGetTime(profile, peak+1);
4039 newlb = MIN(newlb, ect);
4040
4041 /* if the earliest start time is greater than the lst we detected an infeasibilty */
4042 if( newlb > lst )
4043 {
4044 SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4045
4046 /* use conflict analysis to analysis the core insertion which was infeasible */
4047 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4048 var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4049
4050 if( explanation != NULL )
4051 explanation[idx] = TRUE;
4052
4053 *infeasible = TRUE;
4054
4055 break;
4056 }
4057
4058 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4059 * bound change
4060 */
4061 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4062
4063 /* perform the bound lower bound change */
4064 if( inferInfoIsValid(inferinfo) )
4065 {
4066 SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4067 }
4068 else
4069 {
4070 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4071 }
4072 assert(tightened);
4073 assert(!(*infeasible));
4074
4075 SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4076 (*nchgbds)++;
4077
4078 /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4080
4081 /* adjust the earliest start time
4082 *
4083 * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4084 * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4085 * involved.
4086 */
4088 assert(est >= newlb);
4089
4090 /* adjust the search position for the resource profile for the next step */
4091 if( est == SCIPprofileGetTime(profile, peak+1) )
4092 pos = peak + 1;
4093 else
4094 pos = peak;
4095 }
4096 while( est < lst );
4097
4098 return SCIP_OKAY;
4099}
4100
4101/** We are using the core resource profile which contains all core except the one of the start time variable which we
4102 * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4103 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4104 * analysis
4105 */
4106static
4108 SCIP* scip, /**< SCIP data structure */
4109 SCIP_VAR* var, /**< start time variable to propagate */
4110 int duration, /**< duration of the job */
4111 int demand, /**< demand of the job */
4112 int capacity, /**< cumulative capacity */
4113 SCIP_CONS* cons, /**< constraint which is propagated */
4114 SCIP_PROFILE* profile, /**< resource profile */
4115 int idx, /**< position of the variable to propagate */
4116 int* nchgbds /**< pointer to store the number of bound changes */
4117 )
4118{
4119 int ntimepoints;
4120 int newub;
4121 int peak;
4122 int pos;
4123 int est;
4124 int lst;
4125 int lct;
4126
4127 assert(var != NULL);
4128 assert(duration > 0);
4129 assert(demand > 0);
4130
4133
4134 /* in case the start time variable is fixed do nothing */
4135 if( est == lst )
4136 return SCIP_OKAY;
4137
4138 ntimepoints = SCIPprofileGetNTimepoints(profile);
4139
4140 lct = lst + duration;
4141
4142 /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4143 * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4144 * position gives us the load which we have at the latest completion time minus one
4145 */
4146 (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4147
4148 SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4150
4151 if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4152 return SCIP_OKAY;
4153
4154 /* we now trying to move the latest start time in steps of at most "duration" length */
4155 do
4156 {
4157 INFERINFO inferinfo;
4158 SCIP_Bool tightened;
4159 SCIP_Bool infeasible;
4160
4161 peak = -1;
4162
4163#ifndef NDEBUG
4164 {
4165 /* in debug mode we check that we adjust the search position correctly */
4166 int tmppos;
4167
4168 (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4169 assert(pos == tmppos);
4170 }
4171#endif
4172
4173 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4174 * want a peak which is closest to the latest start time
4175 */
4176 do
4177 {
4178 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4179 peak = pos;
4180
4181 pos--;
4182 }
4183 while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4184
4185 /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4186 * to the core resource profile
4187 */
4188 /* coverity[check_after_sink] */
4189 if( peak == -1 )
4190 break;
4191
4192 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4193 * profile. That means the job has be done until that point. Hence that gives us the latest completion
4194 * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4195 * doing in the next loop)
4196 */
4197 newub = SCIPprofileGetTime(profile, peak);
4198 newub = MAX(newub, lst) - duration;
4199 assert(newub >= est);
4200
4201 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4202 * bound change
4203 */
4204 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4205
4206 /* perform the bound upper bound change */
4207 if( inferInfoIsValid(inferinfo) )
4208 {
4209 SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4210 }
4211 else
4212 {
4213 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4214 }
4215 assert(tightened);
4216 assert(!infeasible);
4217
4218 SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4219 (*nchgbds)++;
4220
4221 /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4223
4224 /* adjust the latest start and completion time
4225 *
4226 * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4227 * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4228 * involved.
4229 */
4231 assert(lst <= newub);
4232 lct = lst + duration;
4233
4234 /* adjust the search position for the resource profile for the next step */
4235 if( SCIPprofileGetTime(profile, peak) == lct )
4236 pos = peak - 1;
4237 else
4238 pos = peak;
4239 }
4240 while( est < lst );
4241
4242 return SCIP_OKAY;
4243}
4244
4245/** compute for the different earliest start and latest completion time the core energy of the corresponding time
4246 * points
4247 */
4248static
4250 SCIP_PROFILE* profile, /**< core profile */
4251 int nvars, /**< number of start time variables (activities) */
4252 int* ests, /**< array of sorted earliest start times */
4253 int* lcts, /**< array of sorted latest completion times */
4254 int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4255 int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4256 )
4257{
4258 int ntimepoints;
4259 int energy;
4260 int t;
4261 int v;
4262
4263 ntimepoints = SCIPprofileGetNTimepoints(profile);
4264 t = ntimepoints - 1;
4265 energy = 0;
4266
4267 /* compute core energy after the earliest start time of each job */
4268 for( v = nvars-1; v >= 0; --v )
4269 {
4270 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4271 {
4272 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4273 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4274 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4275 t--;
4276 }
4277 assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4278
4279 /* maybe ests[j] is in-between two timepoints */
4280 if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4281 {
4282 assert(t > 0);
4283 coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4284 }
4285 else
4286 coreEnergyAfterEst[v] = energy;
4287 }
4288
4289 t = ntimepoints - 1;
4290 energy = 0;
4291
4292 /* compute core energy after the latest completion time of each job */
4293 for( v = nvars-1; v >= 0; --v )
4294 {
4295 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4296 {
4297 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4298 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4299 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4300 t--;
4301 }
4302 assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4303
4304 /* maybe lcts[j] is in-between two timepoints */
4305 if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4306 {
4307 assert(t > 0);
4308 coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4309 }
4310 else
4311 coreEnergyAfterLct[v] = energy;
4312 }
4313}
4314
4315/** collect earliest start times, latest completion time, and free energy contributions */
4316static
4318 SCIP* scip, /**< SCIP data structure */
4319 int nvars, /**< number of start time variables (activities) */
4320 SCIP_VAR** vars, /**< array of start time variables */
4321 int* durations, /**< array of durations */
4322 int* demands, /**< array of demands */
4323 int hmin, /**< left bound of time axis to be considered (including hmin) */
4324 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4325 int* permests, /**< array to store the variable positions */
4326 int* ests, /**< array to store earliest start times */
4327 int* permlcts, /**< array to store the variable positions */
4328 int* lcts, /**< array to store latest completion times */
4329 int* ects, /**< array to store earliest completion times of the flexible part of the job */
4330 int* lsts, /**< array to store latest start times of the flexible part of the job */
4331 int* flexenergies /**< array to store the flexible energies of each job */
4332 )
4333{
4334 int v;
4335
4336 for( v = 0; v < nvars; ++ v)
4337 {
4338 int duration;
4339 int leftadjust;
4340 int rightadjust;
4341 int core;
4342 int est;
4343 int lct;
4344 int ect;
4345 int lst;
4346
4347 duration = durations[v];
4348 assert(duration > 0);
4349
4352 ect = est + duration;
4353 lct = lst + duration;
4354
4355 ests[v] = est;
4356 lcts[v] = lct;
4357 permests[v] = v;
4358 permlcts[v] = v;
4359
4360 /* compute core time window which lies within the effective horizon */
4361 core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4362
4363 /* compute the number of time steps the job could run before the effective horizon */
4364 leftadjust = MAX(0, hmin - est);
4365
4366 /* compute the number of time steps the job could run after the effective horizon */
4367 rightadjust = MAX(0, lct - hmax);
4368
4369 /* compute for each job the energy which is flexible; meaning not part of the core */
4370 flexenergies[v] = duration - leftadjust - rightadjust - core;
4371 flexenergies[v] = MAX(0, flexenergies[v]);
4372 flexenergies[v] *= demands[v];
4373 assert(flexenergies[v] >= 0);
4374
4375 /* the earliest completion time of the flexible energy */
4376 ects[v] = MIN(ect, lst);
4377
4378 /* the latest start time of the flexible energy */
4379 lsts[v] = MAX(ect, lst);
4380 }
4381}
4382
4383/** try to tighten the lower bound of the given variable */
4384static
4386 SCIP* scip, /**< SCIP data structure */
4387 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4388 int nvars, /**< number of start time variables (activities) */
4389 SCIP_VAR** vars, /**< array of start time variables */
4390 int* durations, /**< array of durations */
4391 int* demands, /**< array of demands */
4392 int capacity, /**< cumulative capacity */
4393 int hmin, /**< left bound of time axis to be considered (including hmin) */
4394 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4395 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4396 int duration, /**< duration of the job */
4397 int demand, /**< demand of the job */
4398 int est, /**< earliest start time of the job */
4399 int ect, /**< earliest completion time of the flexible part of the job */
4400 int lct, /**< latest completion time of the job */
4401 int begin, /**< begin of the time window under investigation */
4402 int end, /**< end of the time window under investigation */
4403 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4404 int* bestlb, /**< pointer to strope the best lower bound change */
4405 int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4406 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4407 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4408 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4409 )
4410{
4411 int newlb;
4412
4413 assert(begin >= hmin);
4414 assert(end <= hmax);
4415
4416 /* check if the time-table edge-finding should infer bounds */
4417 if( !conshdlrdata->ttefinfer )
4418 return SCIP_OKAY;
4419
4420 /* if the job can be processed completely before or after the time window, nothing can be tightened */
4421 if( est >= end || ect <= begin )
4422 return SCIP_OKAY;
4423
4424 /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4425 * skip since the overload check will do the job
4426 */
4427 if( est >= begin && ect <= end )
4428 return SCIP_OKAY;
4429
4430 /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4431 * earliest start time
4432 */
4433 if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4434 return SCIP_OKAY;
4435
4436 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4437 * present; therefore, we need to add the core;
4438 *
4439 * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4440 * compute the earliest completion time of the (whole) job
4441 */
4442 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4443
4444 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4445 *
4446 * @note we can round down the compute duration w.r.t. the available energy
4447 */
4448 newlb = end - (int) (energy / demand);
4449
4450 /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4451 * bound (latest start time); meaning it is not possible to schedule the job
4452 */
4453 if( newlb > lct - duration )
4454 {
4455 /* initialize conflict analysis if conflict analysis is applicable */
4457 {
4458 SCIP_Real relaxedbd;
4459
4460 assert(boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4461
4462 /* it is enough to overshoot the upper bound of the variable by one */
4463 relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4464
4465 /* initialize conflict analysis */
4467
4468 /* added to upper bound (which was overcut be new lower bound) of the variable */
4470
4471 /* analyze the infeasible */
4472 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4473 begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4474
4475 (*initialized) = TRUE;
4476 }
4477
4478 (*cutoff) = TRUE;
4479 }
4480 else if( newlb > (*bestlb) )
4481 {
4482 INFERINFO inferinfo;
4483
4484 assert(newlb > begin);
4485
4486 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4487
4488 /* construct inference information */
4489 (*inferinfos) = inferInfoToInt(inferinfo);
4490 (*bestlb) = newlb;
4491 }
4492
4493 return SCIP_OKAY;
4494}
4495
4496/** try to tighten the upper bound of the given variable */
4497static
4499 SCIP* scip, /**< SCIP data structure */
4500 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4501 int nvars, /**< number of start time variables (activities) */
4502 SCIP_VAR** vars, /**< array of start time variables */
4503 int* durations, /**< array of durations */
4504 int* demands, /**< array of demands */
4505 int capacity, /**< cumulative capacity */
4506 int hmin, /**< left bound of time axis to be considered (including hmin) */
4507 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4508 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4509 int duration, /**< duration of the job */
4510 int demand, /**< demand of the job */
4511 int est, /**< earliest start time of the job */
4512 int lst, /**< latest start time of the flexible part of the job */
4513 int lct, /**< latest completion time of the job */
4514 int begin, /**< begin of the time window under investigation */
4515 int end, /**< end of the time window under investigation */
4516 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4517 int* bestub, /**< pointer to strope the best upper bound change */
4518 int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4519 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4520 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4521 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4522 )
4523{
4524 int newub;
4525
4526 assert(begin >= hmin);
4527 assert(end <= hmax);
4528 assert(est < begin);
4529
4530 /* check if the time-table edge-finding should infer bounds */
4531 if( !conshdlrdata->ttefinfer )
4532 return SCIP_OKAY;
4533
4534 /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4535 if( lst >= end || lct <= begin )
4536 return SCIP_OKAY;
4537
4538 /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4539 * skip since the overload check will do the job
4540 */
4541 if( lst >= begin && lct <= end )
4542 return SCIP_OKAY;
4543
4544 /* check if the available energy in the time window is to small to handle the flexible part of the job */
4545 if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4546 return SCIP_OKAY;
4547
4548 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4549 * present; therefore, we need to add the core;
4550 *
4551 * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4552 * latest start of the (whole) job
4553 */
4554 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4555 assert(energy >= 0);
4556
4557 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4558 *
4559 * @note we can round down the compute duration w.r.t. the available energy
4560 */
4561 assert(demand > 0);
4562 newub = begin - duration + (int) (energy / demand);
4563
4564 /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4565 * bound (earliest start time); meaning it is not possible to schedule the job
4566 */
4567 if( newub < est )
4568 {
4569 /* initialize conflict analysis if conflict analysis is applicable */
4571 {
4572 SCIP_Real relaxedbd;
4573
4574 assert(boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4575
4576 /* it is enough to undershoot the lower bound of the variable by one */
4577 relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4578
4579 /* initialize conflict analysis */
4581
4582 /* added to lower bound (which was undercut be new upper bound) of the variable */
4584
4585 /* analyze the infeasible */
4586 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4587 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4588
4589 (*initialized) = TRUE;
4590 }
4591
4592 (*cutoff) = TRUE;
4593 }
4594 else if( newub < (*bestub) )
4595 {
4596 INFERINFO inferinfo;
4597
4598 assert(newub < begin);
4599
4600 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4601
4602 /* construct inference information */
4603 (*inferinfos) = inferInfoToInt(inferinfo);
4604 (*bestub) = newub;
4605 }
4606
4607 return SCIP_OKAY;
4608}
4609
4610/** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4611static
4613 SCIP* scip, /**< SCIP data structure */
4614 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4615 int nvars, /**< number of start time variables (activities) */
4616 SCIP_VAR** vars, /**< array of start time variables */
4617 int* durations, /**< array of durations */
4618 int* demands, /**< array of demands */
4619 int capacity, /**< cumulative capacity */
4620 int hmin, /**< left bound of time axis to be considered (including hmin) */
4621 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4622 int* newlbs, /**< array to buffer new lower bounds */
4623 int* newubs, /**< array to buffer new upper bounds */
4624 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4625 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4626 int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4627 int* flexenergies, /**< array of flexible energies in the same order as the variables */
4628 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4629 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4630 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4631 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4632 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4633 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4634 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4635 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4636 )
4637{
4638 int coreEnergyAfterEnd;
4639 SCIP_Longint maxavailable;
4640 SCIP_Longint minavailable;
4641 SCIP_Longint totalenergy;
4642 int nests;
4643 int est;
4644 int lct;
4645 int start;
4646 int end;
4647 int v;
4648
4649 est = INT_MAX;
4650 lct = INT_MIN;
4651
4652 /* compute earliest start and latest completion time of all jobs */
4653 for( v = 0; v < nvars; ++v )
4654 {
4656 end = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4657
4658 est = MIN(est, start);
4659 lct = MAX(lct, end);
4660 }
4661
4662 /* adjust the effective time horizon */
4663 hmin = MAX(hmin, est);
4664 hmax = MIN(hmax, lct);
4665
4666 end = hmax + 1;
4667 coreEnergyAfterEnd = -1;
4668
4669 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4670 minavailable = maxavailable;
4671 totalenergy = computeTotalEnergy(durations, demands, nvars);
4672
4673 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4674 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4675 return SCIP_OKAY;
4676
4677 nests = nvars;
4678
4679 /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4680 * times define the end of the time interval under investigation
4681 */
4682 for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4683 {
4684 int flexenergy;
4685 int minbegin;
4686 int lbenergy;
4687 int lbcand;
4688 int i;
4689
4690 lct = lcts[v];
4691
4692 /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4693 * infinity capacity is available; hence we skip that
4694 */
4695 if( lct > hmax )
4696 continue;
4697
4698 /* if the latest completion time is smaller then hmin we have to stop */
4699 if( lct <= hmin )
4700 {
4701 assert(v == 0 || lcts[v-1] <= lcts[v]);
4702 break;
4703 }
4704
4705 /* if the latest completion time equals to previous end time, we can continue since this particular interval
4706 * induced by end was just analyzed
4707 */
4708 if( lct == end )
4709 continue;
4710
4711 assert(lct < end);
4712
4713 /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4714 * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4715 * free energy; if so it means that in the next iterate the free-energy cannot be negative
4716 */
4717 if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4718 {
4719 SCIP_Longint freeenergy;
4720
4721 assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4722 assert(coreEnergyAfterEnd >= 0);
4723
4724 /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4725 freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4726
4727 if( freeenergy <= minavailable )
4728 {
4729 SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4730 continue;
4731 }
4732 }
4733
4734 SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4735
4736 end = lct;
4737 coreEnergyAfterEnd = coreEnergyAfterLct[v];
4738
4739 flexenergy = 0;
4740 minavailable = maxavailable;
4741 minbegin = hmax;
4742 lbcand = -1;
4743 lbenergy = 0;
4744
4745 /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4746 * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4747 * wider
4748 */
4749 for( i = nests-1; i >= 0; --i )
4750 {
4751 SCIP_VAR* var;
4752 SCIP_Longint freeenergy;
4753 int duration;
4754 int demand;
4755 int begin;
4756 int idx;
4757 int lst;
4758
4759 idx = perm[i];
4760 assert(idx >= 0);
4761 assert(idx < nvars);
4762 assert(!(*cutoff));
4763
4764 /* the earliest start time of the job */
4765 est = ests[i];
4766
4767 /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4768 * latest completion times (which define end) are scant in non-increasing order
4769 */
4770 if( end <= est )
4771 {
4772 nests--;
4773 continue;
4774 }
4775
4776 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4777 * current ending time
4778 */
4779 if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4780 break;
4781
4782 var = vars[idx];
4783 assert(var != NULL);
4784
4785 duration = durations[idx];
4786 assert(duration > 0);
4787
4788 demand = demands[idx];
4789 assert(demand > 0);
4790
4791 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4792
4793 /* the latest start time of the free part of the job */
4794 lst = lsts[idx];
4795
4796 /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4797 * investigation; hence the overload check will do the the job
4798 */
4799 assert(est <= minbegin);
4800 if( minavailable < maxavailable && est < minbegin )
4801 {
4802 assert(!(*cutoff));
4803
4804 /* try to tighten the upper bound */
4805 SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4806 var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4807 initialized, explanation, cutoff) );
4808
4809 if( *cutoff )
4810 break;
4811 }
4812
4813 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4814 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4815
4816 begin = est;
4817 assert(boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4818
4819 /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4820 * free energy
4821 */
4822 if( begin < hmin )
4823 break;
4824
4825 /* compute the contribution to the flexible energy */
4826 if( lct <= end )
4827 {
4828 /* if the jobs has to finish before the end, all the energy has to be scheduled */
4829 assert(lst >= begin);
4830 assert(flexenergies[idx] >= 0);
4831 flexenergy += flexenergies[idx];
4832 }
4833 else
4834 {
4835 /* the job partly overlaps with the end */
4836 int candenergy;
4837 int energy;
4838
4839 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4840 * w.r.t. latest start time
4841 *
4842 * @note we need to be aware of the effective horizon
4843 */
4844 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4845 assert(end - lst < duration);
4846 assert(energy >= 0);
4847
4848 /* adjust the flexible energy of the time interval */
4849 flexenergy += energy;
4850
4851 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4852 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4853 assert(candenergy >= 0);
4854
4855 /* check if we found a better candidate */
4856 if( candenergy > lbenergy )
4857 {
4858 lbenergy = candenergy;
4859 lbcand = idx;
4860 }
4861 }
4862
4863 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4864 assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4865
4866 /* compute the energy which is not used yet */
4867 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4868
4869 /* check overload */
4870 if( freeenergy < 0 )
4871 {
4872 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4873
4874 /* initialize conflict analysis if conflict analysis is applicable */
4876 {
4877 /* analyze infeasibilty */
4879
4880 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4882 conshdlrdata->usebdwidening, explanation) );
4883
4884 (*initialized) = TRUE;
4885 }
4886
4887 (*cutoff) = TRUE;
4888
4889 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4891
4892 break;
4893 }
4894
4895 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4896 if( lbenergy > 0 && freeenergy < lbenergy )
4897 {
4898 SCIP_Longint energy;
4899 int newlb;
4900 int ect;
4901
4902 ect = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4903 lst = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4904
4905 /* remove the energy of our job from the ... */
4906 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4907
4908 newlb = end - (int)(energy / demands[lbcand]);
4909
4910 if( newlb > lst )
4911 {
4912 /* initialize conflict analysis if conflict analysis is applicable */
4914 {
4915 SCIP_Real relaxedbd;
4916
4917 /* analyze infeasibilty */
4919
4920 relaxedbd = lst + 1.0;
4921
4922 /* added to upper bound (which was overcut be new lower bound) of the variable */
4923 SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4924
4925 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4926 begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4927 conshdlrdata->usebdwidening, explanation) );
4928
4929 (*initialized) = TRUE;
4930 }
4931
4932 (*cutoff) = TRUE;
4933 break;
4934 }
4935 else if( newlb > newlbs[lbcand] )
4936 {
4937 INFERINFO inferinfo;
4938
4939 /* construct inference information */
4940 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4941
4942 /* buffer upper bound change */
4943 lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4944 newlbs[lbcand] = newlb;
4945 }
4946 }
4947
4948 /* check if the current interval has a smaller free energy */
4949 if( minavailable > freeenergy )
4950 {
4951 minavailable = freeenergy;
4952 minbegin = begin;
4953 }
4954 assert(minavailable >= 0);
4955 }
4956 }
4957
4958 return SCIP_OKAY;
4959}
4960
4961/** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4962static
4964 SCIP* scip, /**< SCIP data structure */
4965 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4966 int nvars, /**< number of start time variables (activities) */
4967 SCIP_VAR** vars, /**< array of start time variables */
4968 int* durations, /**< array of durations */
4969 int* demands, /**< array of demands */
4970 int capacity, /**< cumulative capacity */
4971 int hmin, /**< left bound of time axis to be considered (including hmin) */
4972 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4973 int* newlbs, /**< array to buffer new lower bounds */
4974 int* newubs, /**< array to buffer new upper bounds */
4975 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4976 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4977 int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
4978 int* flexenergies, /**< array of flexible energies in the same order as the variables */
4979 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
4980 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4981 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4982 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4983 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4984 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4985 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4986 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4987 )
4988{
4989 int coreEnergyAfterStart;
4990 SCIP_Longint maxavailable;
4991 SCIP_Longint minavailable;
4992 SCIP_Longint totalenergy;
4993 int nlcts;
4994 int begin;
4995 int minest;
4996 int maxlct;
4997 int start;
4998 int end;
4999 int v;
5000
5001 if( *cutoff )
5002 return SCIP_OKAY;
5003
5004 begin = hmin - 1;
5005
5006 minest = INT_MAX;
5007 maxlct = INT_MIN;
5008
5009 /* compute earliest start and latest completion time of all jobs */
5010 for( v = 0; v < nvars; ++v )
5011 {
5013 end = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5014
5015 minest = MIN(minest, start);
5016 maxlct = MAX(maxlct, end);
5017 }
5018
5019 /* adjust the effective time horizon */
5020 hmin = MAX(hmin, minest);
5021 hmax = MIN(hmax, maxlct);
5022
5023 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5024 totalenergy = computeTotalEnergy(durations, demands, nvars);
5025
5026 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5027 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5028 return SCIP_OKAY;
5029
5030 nlcts = 0;
5031
5032 /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5033 * define the start of the time interval under investigation
5034 */
5035 for( v = 0; v < nvars; ++v )
5036 {
5037 int flexenergy;
5038 int minend;
5039 int ubenergy;
5040 int ubcand;
5041 int est;
5042 int i;
5043
5044 est = ests[v];
5045
5046 /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5047 * infinity capacity is available; hence we skip that
5048 */
5049 if( est < hmin )
5050 continue;
5051
5052 /* if the earliest start time is larger or equal then hmax we have to stop */
5053 if( est >= hmax )
5054 break;
5055
5056 /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5057 * induced by start was just analyzed
5058 */
5059 if( est == begin )
5060 continue;
5061
5062 assert(est > begin);
5063
5064 SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5065
5066 begin = est;
5067 coreEnergyAfterStart = coreEnergyAfterEst[v];
5068
5069 flexenergy = 0;
5070 minavailable = maxavailable;
5071 minend = hmin;
5072 ubcand = -1;
5073 ubenergy = 0;
5074
5075 /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5076 * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5077 */
5078 for( i = nlcts; i < nvars; ++i )
5079 {
5080 SCIP_VAR* var;
5081 SCIP_Longint freeenergy;
5082 int duration;
5083 int demand;
5084 int idx;
5085 int lct;
5086 int ect;
5087
5088 idx = perm[i];
5089 assert(idx >= 0);
5090 assert(idx < nvars);
5091 assert(!(*cutoff));
5092
5093 /* the earliest start time of the job */
5094 lct = lcts[i];
5095
5096 /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5097 * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5098 */
5099 if( lct <= begin )
5100 {
5101 nlcts++;
5102 continue;
5103 }
5104
5105 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5106 * start with current beginning time
5107 */
5108 if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5109 break;
5110
5111 var = vars[idx];
5112 assert(var != NULL);
5113
5114 duration = durations[idx];
5115 assert(duration > 0);
5116
5117 demand = demands[idx];
5118 assert(demand > 0);
5119
5121
5122 /* the earliest completion time of the flexible part of the job */
5123 ect = ects[idx];
5124
5125 /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5126 * investigation; hence the overload check will do the the job
5127 */
5128 assert(lct >= minend);
5129 if( minavailable < maxavailable && lct > minend )
5130 {
5131 assert(!(*cutoff));
5132
5133 /* try to tighten the upper bound */
5134 SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5135 var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5136 initialized, explanation, cutoff) );
5137
5138 if( *cutoff )
5139 return SCIP_OKAY;
5140 }
5141
5142 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5143 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5144
5145 end = lct;
5146 assert(boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5147
5148 /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5149 * free energy
5150 */
5151 if( end > hmax )
5152 break;
5153
5154 /* compute the contribution to the flexible energy */
5155 if( est >= begin )
5156 {
5157 /* if the jobs has to finish before the end, all the energy has to be scheduled */
5158 assert(ect <= end);
5159 assert(flexenergies[idx] >= 0);
5160 flexenergy += flexenergies[idx];
5161 }
5162 else
5163 {
5164 /* the job partly overlaps with the end */
5165 int candenergy;
5166 int energy;
5167
5168 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5169 * w.r.t. latest start time
5170 *
5171 * @note we need to be aware of the effective horizon
5172 */
5173 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5174 assert(ect - begin < duration);
5175 assert(energy >= 0);
5176
5177 /* adjust the flexible energy of the time interval */
5178 flexenergy += energy;
5179
5180 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5181 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5182 assert(candenergy >= 0);
5183
5184 /* check if we found a better candidate */
5185 if( candenergy > ubenergy )
5186 {
5187 ubenergy = candenergy;
5188 ubcand = idx;
5189 }
5190 }
5191
5192 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5193 assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5194
5195 /* compute the energy which is not used yet */
5196 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5197
5198 /* check overload */
5199 if( freeenergy < 0 )
5200 {
5201 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5202
5203 /* initialize conflict analysis if conflict analysis is applicable */
5205 {
5206 /* analyze infeasibilty */
5208
5209 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5211 conshdlrdata->usebdwidening, explanation) );
5212
5213 (*initialized) = TRUE;
5214 }
5215
5216 (*cutoff) = TRUE;
5217
5218 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5220
5221 return SCIP_OKAY;
5222 }
5223
5224 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5225 if( ubenergy > 0 && freeenergy < ubenergy )
5226 {
5227 SCIP_Longint energy;
5228 int newub;
5229 int lst;
5230
5231 duration = durations[ubcand];
5232 assert(duration > 0);
5233
5234 ect = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5235 lst = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5236
5237 /* remove the energy of our job from the ... */
5238 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5239
5240 newub = begin - duration + (int)(energy / demands[ubcand]);
5241
5242 if( newub < ect - duration )
5243 {
5244 /* initialize conflict analysis if conflict analysis is applicable */
5246 {
5247 SCIP_Real relaxedbd;
5248 /* analyze infeasibilty */
5250
5251 relaxedbd = ect - duration - 1.0;
5252
5253 /* added to lower bound (which was undercut be new upper bound) of the variable */
5254 SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5255
5256 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5257 begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5258 conshdlrdata->usebdwidening, explanation) );
5259
5260 (*initialized) = TRUE;
5261 }
5262
5263 (*cutoff) = TRUE;
5264 return SCIP_OKAY;
5265 }
5266 else if( newub < newubs[ubcand] )
5267 {
5268 INFERINFO inferinfo;
5269
5270 /* construct inference information */
5271 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5272
5273 /* buffer upper bound change */
5274 ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5275 newubs[ubcand] = newub;
5276 }
5277 }
5278
5279 /* check if the current interval has a smaller free energy */
5280 if( minavailable > freeenergy )
5281 {
5282 minavailable = freeenergy;
5283 minend = end;
5284 }
5285 assert(minavailable >= 0);
5286 }
5287 }
5288
5289 return SCIP_OKAY;
5290}
5291
5292/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5293 * edge-finding
5294 *
5295 * @note The algorithm is based on the following two papers:
5296 * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5297 * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5298 * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5299 * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5300 * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5301 */
5302static
5304 SCIP* scip, /**< SCIP data structure */
5305 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5306 SCIP_PROFILE* profile, /**< current core profile */
5307 int nvars, /**< number of start time variables (activities) */
5308 SCIP_VAR** vars, /**< array of start time variables */
5309 int* durations, /**< array of durations */
5310 int* demands, /**< array of demands */
5311 int capacity, /**< cumulative capacity */
5312 int hmin, /**< left bound of time axis to be considered (including hmin) */
5313 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5314 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5315 int* nchgbds, /**< pointer to store the number of bound changes */
5316 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5317 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5318 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5319 )
5320{
5321 int* coreEnergyAfterEst;
5322 int* coreEnergyAfterLct;
5323 int* flexenergies;
5324 int* permests;
5325 int* permlcts;
5326 int* lcts;
5327 int* ests;
5328 int* ects;
5329 int* lsts;
5330
5331 int* newlbs;
5332 int* newubs;
5333 int* lbinferinfos;
5334 int* ubinferinfos;
5335
5336 int v;
5337
5338 /* check if a cutoff was already detected */
5339 if( (*cutoff) )
5340 return SCIP_OKAY;
5341
5342 /* check if at least the basic overload checking should be perfomed */
5343 if( !conshdlrdata->ttefcheck )
5344 return SCIP_OKAY;
5345
5346 SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5347
5348 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5349 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5350 SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5351 SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5352 SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5353 SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5354 SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5355 SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5356 SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5357
5358 SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5359 SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5360 SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5361 SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5362
5363 /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5364 for( v = 0; v < nvars; ++v )
5365 {
5366 newlbs[v] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5367 newubs[v] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5368 lbinferinfos[v] = 0;
5369 ubinferinfos[v] = 0;
5370 }
5371
5372 /* collect earliest start times, latest completion time, and free energy contributions */
5373 collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5374
5375 /* sort the earliest start times and latest completion in non-decreasing order */
5376 SCIPsortIntInt(ests, permests, nvars);
5377 SCIPsortIntInt(lcts, permlcts, nvars);
5378
5379 /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5380 * points
5381 */
5382 computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5383
5384 /* propagate the upper bounds and "opportunistically" the lower bounds */
5385 SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5386 newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5387 permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5388
5389 /* propagate the lower bounds and "opportunistically" the upper bounds */
5390 SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5391 newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5392 permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5393
5394 /* apply the buffer bound changes */
5395 for( v = 0; v < nvars && !(*cutoff); ++v )
5396 {
5397 SCIP_Bool infeasible;
5398 SCIP_Bool tightened;
5399
5400 if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5401 {
5402 SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5403 TRUE, &infeasible, &tightened) );
5404 }
5405 else
5406 {
5407 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5408 }
5409
5410 /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5411 assert(!infeasible);
5412
5413 if( tightened )
5414 {
5415 (*nchgbds)++;
5416
5417 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5419 }
5420
5421 if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5422 {
5423 SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5424 TRUE, &infeasible, &tightened) );
5425 }
5426 else
5427 {
5428 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5429 }
5430
5431 /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5432 * bound update can be infeasible
5433 */
5434 if( infeasible )
5435 {
5436 /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5437 * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5438 * be analyzed in the case when begin and end exceed the 15 bit limit
5439 */
5441 {
5442 INFERINFO inferinfo;
5443 SCIP_VAR* var;
5444 int begin;
5445 int end;
5446
5447 var = vars[v];
5448 assert(var != NULL);
5449
5450 /* initialize conflict analysis */
5452
5453 /* convert int to inference information */
5454 inferinfo = intToInferInfo(ubinferinfos[v]);
5455
5456 /* collect time window from inference information */
5457 begin = inferInfoGetData1(inferinfo);
5458 end = inferInfoGetData2(inferinfo);
5459 assert(begin < end);
5460
5461 /* added to lower bound (which was undercut be new upper bound) of the variable */
5463
5464 /* analysis the upper bound change */
5465 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5466 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5467 conshdlrdata->usebdwidening, explanation) );
5468
5469 (*initialized) = TRUE;
5470 }
5471
5472 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5474
5475 (*cutoff) = TRUE;
5476 break;
5477 }
5478
5479 if( tightened )
5480 {
5481 (*nchgbds)++;
5482
5483 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5485 }
5486 }
5487
5488 SCIPfreeBufferArray(scip, &ubinferinfos);
5489 SCIPfreeBufferArray(scip, &lbinferinfos);
5490 SCIPfreeBufferArray(scip, &newubs);
5491 SCIPfreeBufferArray(scip, &newlbs);
5492
5493 /* free buffer arrays */
5494 SCIPfreeBufferArray(scip, &lsts);
5495 SCIPfreeBufferArray(scip, &ects);
5496 SCIPfreeBufferArray(scip, &ests);
5497 SCIPfreeBufferArray(scip, &lcts);
5498 SCIPfreeBufferArray(scip, &permests);
5499 SCIPfreeBufferArray(scip, &permlcts);
5500 SCIPfreeBufferArray(scip, &flexenergies);
5501 SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5502 SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5503
5504 return SCIP_OKAY;
5505}
5506
5507/** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5508 * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5509 * time table propagator
5510 */
5511static
5513 SCIP* scip, /**< SCIP data structure */
5514 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5515 SCIP_PROFILE* profile, /**< core profile */
5516 int nvars, /**< number of start time variables (activities) */
5517 SCIP_VAR** vars, /**< array of start time variables */
5518 int* durations, /**< array of durations */
5519 int* demands, /**< array of demands */
5520 int capacity, /**< cumulative capacity */
5521 int hmin, /**< left bound of time axis to be considered (including hmin) */
5522 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5523 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5524 int* nchgbds, /**< pointer to store the number of bound changes */
5525 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5526 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5527 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5528 )
5529{
5530 SCIP_Bool infeasible;
5531 int v;
5532
5533 assert(scip != NULL);
5534 assert(nvars > 0);
5535 assert(cons != NULL);
5536 assert(cutoff != NULL);
5537
5538 /* check if already a cutoff was detected */
5539 if( (*cutoff) )
5540 return SCIP_OKAY;
5541
5542 /* check if the time tabling should infer bounds */
5543 if( !conshdlrdata->ttinfer )
5544 return SCIP_OKAY;
5545
5546 assert(*initialized == FALSE);
5547
5548 SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5549 SCIPconsGetName(cons), hmin, hmax, capacity);
5550
5551 infeasible = FALSE;
5552
5553 /* if core profile is empty; nothing to do */
5554 if( SCIPprofileGetNTimepoints(profile) <= 1 )
5555 return SCIP_OKAY;
5556
5557 /* start checking each job whether the bounds can be improved */
5558 for( v = 0; v < nvars; ++v )
5559 {
5560 SCIP_VAR* var;
5561 int demand;
5562 int duration;
5563 int begin;
5564 int end;
5565 int est;
5566 int lst;
5567
5568 var = vars[v];
5569 assert(var != NULL);
5570
5571 duration = durations[v];
5572 assert(duration > 0);
5573
5574 /* collect earliest and latest start time */
5577
5578 /* check if the start time variables is already fixed; in that case we can ignore the job */
5579 if( est == lst )
5580 continue;
5581
5582 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5583 if( lst + duration <= hmin || est >= hmax )
5584 continue;
5585
5586 /* compute core interval w.r.t. effective time horizon */
5587 begin = MAX(hmin, lst);
5588 end = MIN(hmax, est + duration);
5589
5590 demand = demands[v];
5591 assert(demand > 0);
5592
5593 /* if the job has a core, remove it first */
5594 if( begin < end )
5595 {
5596 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5597 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5598
5599 SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5600 }
5601
5602 /* first try to update the earliest start time */
5603 SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5604 profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5605
5606 if( *cutoff )
5607 break;
5608
5609 /* second try to update the latest start time */
5610 SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5611 profile, v, nchgbds) );
5612
5613 if( *cutoff )
5614 break;
5615
5616 /* collect the potentially updated earliest and latest start time */
5619
5620 /* compute core interval w.r.t. effective time horizon */
5621 begin = MAX(hmin, lst);
5622 end = MIN(hmax, est + duration);
5623
5624 /* after updating the bound we might have a new core */
5625 if( begin < end )
5626 {
5627 int pos;
5628
5629 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5630 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5631
5632 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5633
5634 if( infeasible )
5635 {
5636 /* use conflict analysis to analysis the core insertion which was infeasible */
5637 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5638 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5639
5640 if( explanation != NULL )
5641 explanation[v] = TRUE;
5642
5643 (*cutoff) = TRUE;
5644
5645 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5647
5648 break;
5649 }
5650 }
5651 }
5652
5653 return SCIP_OKAY;
5654}
5655
5656
5657/** node data structure for the binary tree used for edgefinding (with overload checking) */
5658struct SCIP_NodeData
5659{
5660 SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5661 SCIP_Real key; /**< key which is to insert the corresponding search node */
5662 int est; /**< earliest start time if the node data belongs to a leaf */
5663 int lct; /**< latest completion time if the node data belongs to a leaf */
5664 int demand; /**< demand of the job if the node data belongs to a leaf */
5665 int duration; /**< duration of the job if the node data belongs to a leaf */
5666 int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5667 int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5668 SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5669 int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5670 int energylambda;
5671 SCIP_Longint enveloplambda;
5672 int idx; /**< index of the start time variable in the (global) variable array */
5673 SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5674};
5675typedef struct SCIP_NodeData SCIP_NODEDATA;
5676
5677
5678/** update node data structure starting from the given node along the path to the root node */
5679static
5681 SCIP* scip, /**< SCIP data structure */
5682 SCIP_BTNODE* node /**< search node which inserted */
5683 )
5684{
5685 SCIP_BTNODE* left;
5686 SCIP_BTNODE* right;
5688 SCIP_NODEDATA* leftdata;
5689 SCIP_NODEDATA* rightdata;
5690
5691 SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5692
5693 if( SCIPbtnodeIsLeaf(node) )
5694 node = SCIPbtnodeGetParent(node);
5695
5696 while( node != NULL )
5697 {
5698 /* get node data */
5700 assert(nodedata != NULL);
5701
5702 /* collect node data from left node */
5703 left = SCIPbtnodeGetLeftchild(node);
5704 assert(left != NULL);
5705 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5706 assert(leftdata != NULL);
5707
5708 /* collect node data from right node */
5709 right = SCIPbtnodeGetRightchild(node);
5710 assert(right != NULL);
5711 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5712 assert(rightdata != NULL);
5713
5714 /* update envelop and energy */
5715 if( leftdata->enveloptheta >= 0 )
5716 {
5717 assert(rightdata->energytheta != -1);
5718 nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5719 }
5720 else
5721 nodedata->enveloptheta = rightdata->enveloptheta;
5722
5723 assert(leftdata->energytheta != -1);
5724 assert(rightdata->energytheta != -1);
5725 nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5726
5727 if( leftdata->enveloplambda >= 0 )
5728 {
5729 assert(rightdata->energytheta != -1);
5730 nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5731 }
5732 else
5733 nodedata->enveloplambda = rightdata->enveloplambda;
5734
5735 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5736 nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5737
5738 SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5739
5740 if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5741 {
5742 assert(rightdata->energytheta != -1);
5743 assert(leftdata->energytheta != -1);
5744 nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5745 }
5746 else if( rightdata->energylambda >= 0 )
5747 {
5748 assert(leftdata->energytheta != -1);
5749 nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5750 }
5751 else if( leftdata->energylambda >= 0 )
5752 {
5753 assert(rightdata->energytheta != -1);
5754 nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5755 }
5756 else
5757 nodedata->energylambda = -1;
5758
5759 /* go to parent */
5760 node = SCIPbtnodeGetParent(node);
5761 }
5762
5763 SCIPdebugMsg(scip, "updating done\n");
5764}
5765
5766/** updates the key of the first parent on the trace which comes from left */
5767static
5769 SCIP_BTNODE* node, /**< node to start the trace */
5770 SCIP_Real key /**< update search key */
5771 )
5772{
5773 assert(node != NULL);
5774
5775 while( !SCIPbtnodeIsRoot(node) )
5776 {
5777 SCIP_BTNODE* parent;
5778
5779 parent = SCIPbtnodeGetParent(node);
5780 assert(parent != NULL);
5781
5782 if( SCIPbtnodeIsLeftchild(node) )
5783 {
5785
5787 assert(nodedata != NULL);
5788
5789 nodedata->key = key;
5790 return;
5791 }
5792
5793 node = parent;
5794 }
5795}
5796
5797
5798/** deletes the given node and updates all envelops */
5799static
5801 SCIP* scip, /**< SCIP data structure */
5802 SCIP_BT* tree, /**< binary tree */
5803 SCIP_BTNODE* node /**< node to be deleted */
5804 )
5805{
5806 SCIP_BTNODE* parent;
5807 SCIP_BTNODE* grandparent;
5808 SCIP_BTNODE* sibling;
5809
5810 assert(scip != NULL);
5811 assert(tree != NULL);
5812 assert(node != NULL);
5813
5814 assert(SCIPbtnodeIsLeaf(node));
5815 assert(!SCIPbtnodeIsRoot(node));
5816
5817 SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5818
5819 parent = SCIPbtnodeGetParent(node);
5820 assert(parent != NULL);
5821 if( SCIPbtnodeIsLeftchild(node) )
5822 {
5823 sibling = SCIPbtnodeGetRightchild(parent);
5825 }
5826 else
5827 {
5828 sibling = SCIPbtnodeGetLeftchild(parent);
5830 }
5831 assert(sibling != NULL);
5832
5833 grandparent = SCIPbtnodeGetParent(parent);
5834
5835 if( grandparent != NULL )
5836 {
5837 /* reset parent of sibling */
5838 SCIPbtnodeSetParent(sibling, grandparent);
5839
5840 /* reset child of grandparent to sibling */
5841 if( SCIPbtnodeIsLeftchild(parent) )
5842 {
5843 SCIPbtnodeSetLeftchild(grandparent, sibling);
5844 }
5845 else
5846 {
5848
5849 assert(SCIPbtnodeIsRightchild(parent));
5850 SCIPbtnodeSetRightchild(grandparent, sibling);
5851
5853
5854 updateKeyOnTrace(grandparent, nodedata->key);
5855 }
5856
5857 updateEnvelope(scip, grandparent);
5858 }
5859 else
5860 {
5861 SCIPbtnodeSetParent(sibling, NULL);
5862
5863 SCIPbtSetRoot(tree, sibling);
5864 }
5865
5866 SCIPbtnodeFree(tree, &parent);
5867
5868 return SCIP_OKAY;
5869}
5870
5871/** moves a node form the theta set into the lambda set and updates the envelops */
5872static
5874 SCIP* scip, /**< SCIP data structure */
5875 SCIP_BT* tree, /**< binary tree */
5876 SCIP_BTNODE* node /**< node to move into the lambda set */
5877 )
5878{
5880
5881 assert(scip != NULL);
5882 assert(tree != NULL);
5883 assert(node != NULL);
5884
5886 assert(nodedata != NULL);
5887 assert(nodedata->intheta);
5888
5889 /* move the contributions form the theta set into the lambda set */
5890 assert(nodedata->enveloptheta != -1);
5891 assert(nodedata->energytheta != -1);
5892 assert(nodedata->enveloplambda == -1);
5893 assert(nodedata->energylambda == -1);
5894 nodedata->enveloplambda = nodedata->enveloptheta;
5895 nodedata->energylambda = nodedata->energytheta;
5896
5897 nodedata->enveloptheta = -1;
5898 nodedata->energytheta = 0;
5899 nodedata->intheta = FALSE;
5900
5901 /* update the energy and envelop values on trace */
5902 updateEnvelope(scip, node);
5903
5904 return SCIP_OKAY;
5905}
5906
5907/** inserts a node into the theta set and update the envelops */
5908static
5910 SCIP* scip, /**< SCIP data structure */
5911 SCIP_BT* tree, /**< binary tree */
5912 SCIP_BTNODE* node, /**< node to insert */
5913 SCIP_NODEDATA* nodedatas, /**< array of node data */
5914 int* nodedataidx, /**< array of indices for node data */
5915 int* nnodedatas /**< pointer to number of node data */
5916 )
5917{
5918 /* if the tree is empty the node will be the root node */
5919 if( SCIPbtIsEmpty(tree) )
5920 {
5921 SCIPbtSetRoot(tree, node);
5922 }
5923 else
5924 {
5925 SCIP_NODEDATA* newnodedata;
5926 SCIP_NODEDATA* leafdata;
5928 SCIP_BTNODE* leaf;
5929 SCIP_BTNODE* newnode;
5930 SCIP_BTNODE* parent;
5931
5932 leaf = SCIPbtGetRoot(tree);
5933 assert(leaf != NULL);
5934
5935 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5936 assert(leafdata != NULL);
5937
5939 assert(nodedata != NULL);
5940 assert(nodedata->intheta);
5941
5942 /* find the position to insert the node */
5943 while( !SCIPbtnodeIsLeaf(leaf) )
5944 {
5945 if( nodedata->key < leafdata->key )
5946 leaf = SCIPbtnodeGetLeftchild(leaf);
5947 else
5948 leaf = SCIPbtnodeGetRightchild(leaf);
5949
5950 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5951 assert(leafdata != NULL);
5952 }
5953
5954 assert(leaf != NULL);
5955 assert(leaf != node);
5956
5957 /* store node data to be able to delete them latter */
5958 newnodedata = &nodedatas[*nnodedatas];
5959 nodedataidx[*nnodedatas] = *nnodedatas;
5960 ++(*nnodedatas);
5961
5962 /* init node data */
5963 newnodedata->var = NULL;
5964 newnodedata->key = SCIP_INVALID;
5965 newnodedata->est = INT_MIN;
5966 newnodedata->lct = INT_MAX;
5967 newnodedata->duration = 0;
5968 newnodedata->demand = 0;
5969 newnodedata->enveloptheta = -1;
5970 newnodedata->energytheta = 0;
5971 newnodedata->enveloplambda = -1;
5972 newnodedata->energylambda = -1;
5973 newnodedata->idx = -1;
5974 newnodedata->intheta = TRUE;
5975
5976 /* create a new node */
5977 SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
5978 assert(newnode != NULL);
5979
5980 parent = SCIPbtnodeGetParent(leaf);
5981
5982 if( parent != NULL )
5983 {
5984 SCIPbtnodeSetParent(newnode, parent);
5985
5986 /* check if the node is the left child */
5987 if( SCIPbtnodeGetLeftchild(parent) == leaf )
5988 {
5989 SCIPbtnodeSetLeftchild(parent, newnode);
5990 }
5991 else
5992 {
5993 SCIPbtnodeSetRightchild(parent, newnode);
5994 }
5995 }
5996 else
5997 SCIPbtSetRoot(tree, newnode);
5998
5999 if( nodedata->key < leafdata->key )
6000 {
6001 /* node is on the left */
6002 SCIPbtnodeSetLeftchild(newnode, node);
6003 SCIPbtnodeSetRightchild(newnode, leaf);
6004 newnodedata->key = nodedata->key;
6005 }
6006 else
6007 {
6008 /* leaf is on the left */
6009 SCIPbtnodeSetLeftchild(newnode, leaf);
6010 SCIPbtnodeSetRightchild(newnode, node);
6011 newnodedata->key = leafdata->key;
6012 }
6013
6014 SCIPbtnodeSetParent(leaf, newnode);
6015 SCIPbtnodeSetParent(node, newnode);
6016 }
6017
6018 /* update envelop */
6019 updateEnvelope(scip, node);
6020
6021 return SCIP_OKAY;
6022}
6023
6024/** returns the leaf responsible for the lambda energy */
6025static
6027 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6028 )
6029{
6030 SCIP_BTNODE* left;
6031 SCIP_BTNODE* right;
6033 SCIP_NODEDATA* leftdata;
6034 SCIP_NODEDATA* rightdata;
6035
6036 assert(node != NULL);
6037
6039 assert(nodedata != NULL);
6040
6041 /* check if the node is the (responsible) leaf */
6042 if( SCIPbtnodeIsLeaf(node) )
6043 {
6044 assert(!nodedata->intheta);
6045 return node;
6046 }
6047
6048 left = SCIPbtnodeGetLeftchild(node);
6049 assert(left != NULL);
6050
6051 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6052 assert(leftdata != NULL);
6053
6054 right = SCIPbtnodeGetRightchild(node);
6055 assert(right != NULL);
6056
6057 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6058 assert(rightdata != NULL);
6059
6060 assert(nodedata->energylambda != -1);
6061 assert(rightdata->energytheta != -1);
6062
6063 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6065
6066 assert(leftdata->energytheta != -1);
6067 assert(rightdata->energylambda != -1);
6068 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6069
6071}
6072
6073/** returns the leaf responsible for the lambda envelop */
6074static
6076 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6077 )
6078{
6079 SCIP_BTNODE* left;
6080 SCIP_BTNODE* right;
6082 SCIP_NODEDATA* leftdata;
6083 SCIP_NODEDATA* rightdata;
6084
6085 assert(node != NULL);
6086
6088 assert(nodedata != NULL);
6089
6090 /* check if the node is the (responsible) leaf */
6091 if( SCIPbtnodeIsLeaf(node) )
6092 {
6093 assert(!nodedata->intheta);
6094 return node;
6095 }
6096
6097 left = SCIPbtnodeGetLeftchild(node);
6098 assert(left != NULL);
6099
6100 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6101 assert(leftdata != NULL);
6102
6103 right = SCIPbtnodeGetRightchild(node);
6104 assert(right != NULL);
6105
6106 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6107 assert(rightdata != NULL);
6108
6109 assert(nodedata->enveloplambda != -1);
6110 assert(rightdata->energytheta != -1);
6111
6112 /* check if the left or right child is the one defining the envelop for the lambda set */
6113 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6115 else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6116 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6118
6119 assert(rightdata->enveloplambda != -1);
6120 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6121
6123}
6124
6125
6126/** reports all elements from set theta to generate a conflicting set */
6127static
6129 SCIP_BTNODE* node, /**< node within a theta subtree */
6130 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6131 int* nelements, /**< pointer to store the number of elements in omegaset */
6132 int* est, /**< pointer to store the earliest start time of the omega set */
6133 int* lct, /**< pointer to store the latest start time of the omega set */
6134 int* energy /**< pointer to store the energy of the omega set */
6135 )
6136{
6138
6140 assert(nodedata != NULL);
6141
6142 if( !SCIPbtnodeIsLeaf(node) )
6143 {
6144 collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6145 collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6146 }
6147 else if( nodedata->intheta )
6148 {
6149 assert(nodedata->var != NULL);
6150 SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6151
6152 omegaset[*nelements] = node;
6153 (*est) = MIN(*est, nodedata->est);
6154 (*lct) = MAX(*lct, nodedata->lct);
6155 (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6156 (*nelements)++;
6157 }
6158}
6159
6160
6161/** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6162static
6164 SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6165 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6166 int* nelements, /**< pointer to store the number of elements in omegaset */
6167 int* est, /**< pointer to store the earliest start time of the omega set */
6168 int* lct, /**< pointer to store the latest start time of the omega set */
6169 int* energy /**< pointer to store the energy of the omega set */
6170 )
6171{
6172 assert(node != NULL);
6173
6174 if( SCIPbtnodeIsLeaf(node) )
6175 {
6176 collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6177 }
6178 else
6179 {
6180 SCIP_BTNODE* left;
6181 SCIP_BTNODE* right;
6183 SCIP_NODEDATA* leftdata;
6184 SCIP_NODEDATA* rightdata;
6185
6187 assert(nodedata != NULL);
6188
6189 left = SCIPbtnodeGetLeftchild(node);
6190 assert(left != NULL);
6191
6192 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6193 assert(leftdata != NULL);
6194
6195 right = SCIPbtnodeGetRightchild(node);
6196 assert(right != NULL);
6197
6198 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6199 assert(rightdata != NULL);
6200
6202 assert(nodedata != NULL);
6203
6204 assert(nodedata->enveloptheta != -1);
6205 assert(rightdata->energytheta != -1);
6206
6207 if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6208 {
6209 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6210 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6211 }
6212 else
6213 {
6214 assert(rightdata->enveloptheta != -1);
6215 assert(nodedata->enveloptheta == rightdata->enveloptheta);
6216 traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6217 }
6218 }
6219}
6220
6221/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6222static
6224 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6225 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6226 int* nelements, /**< pointer to store the number of elements in omega set */
6227 int* est, /**< pointer to store the earliest start time of the omega set */
6228 int* lct, /**< pointer to store the latest start time of the omega set */
6229 int* energy /**< pointer to store the energy of the omega set */
6230 )
6231{
6232 SCIP_BTNODE* left;
6233 SCIP_BTNODE* right;
6235 SCIP_NODEDATA* leftdata;
6236 SCIP_NODEDATA* rightdata;
6237
6238 assert(node != NULL);
6239
6241 assert(nodedata != NULL);
6242
6243 /* check if the node is a leaf */
6244 if( SCIPbtnodeIsLeaf(node) )
6245 return;
6246
6247 left = SCIPbtnodeGetLeftchild(node);
6248 assert(left != NULL);
6249
6250 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6251 assert(leftdata != NULL);
6252
6253 right = SCIPbtnodeGetRightchild(node);
6254 assert(right != NULL);
6255
6256 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6257 assert(rightdata != NULL);
6258
6259 assert(nodedata->energylambda != -1);
6260 assert(rightdata->energytheta != -1);
6261
6262 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6263 {
6264 traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6265 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6266 }
6267 else
6268 {
6269 assert(leftdata->energytheta != -1);
6270 assert(rightdata->energylambda != -1);
6271 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6272
6273 collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6274 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6275 }
6276}
6277
6278/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6279static
6281 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6282 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6283 int* nelements, /**< pointer to store the number of elements in omega set */
6284 int* est, /**< pointer to store the earliest start time of the omega set */
6285 int* lct, /**< pointer to store the latest start time of the omega set */
6286 int* energy /**< pointer to store the energy of the omega set */
6287 )
6288{
6289 SCIP_BTNODE* left;
6290 SCIP_BTNODE* right;
6292 SCIP_NODEDATA* leftdata;
6293 SCIP_NODEDATA* rightdata;
6294
6295 assert(node != NULL);
6296
6298 assert(nodedata != NULL);
6299
6300 /* check if the node is a leaf */
6301 if( SCIPbtnodeIsLeaf(node) )
6302 {
6303 assert(!nodedata->intheta);
6304 return;
6305 }
6306
6307 left = SCIPbtnodeGetLeftchild(node);
6308 assert(left != NULL);
6309
6310 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6311 assert(leftdata != NULL);
6312
6313 right = SCIPbtnodeGetRightchild(node);
6314 assert(right != NULL);
6315
6316 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6317 assert(rightdata != NULL);
6318
6319 assert(nodedata->enveloplambda != -1);
6320 assert(rightdata->energytheta != -1);
6321
6322 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6323 {
6324 traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6325 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6326 }
6327 else
6328 {
6329 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6330 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6331 {
6332 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6333 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6334 }
6335 else
6336 {
6337 assert(rightdata->enveloplambda != -1);
6338 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6339 traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6340 }
6341 }
6342}
6343
6344/** compute the energy contribution by job which corresponds to the given leaf */
6345static
6347 SCIP_BTNODE* node /**< leaf */
6348 )
6349{
6351 int duration;
6352
6354 assert(nodedata != NULL);
6355 assert(nodedata->var != NULL);
6356
6357 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6358 assert(duration > 0);
6359
6360 SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6362 SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6363
6364 /* return energy which is contributed by the start time variable */
6365 return nodedata->demand * duration;
6366}
6367
6368/** comparison method for two node data w.r.t. the earliest start time */
6369static
6371{
6372 int est1;
6373 int est2;
6374
6375 est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6376 est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6377
6378 return (est1 - est2);
6379}
6380
6381/** comparison method for two node data w.r.t. the latest completion time */
6382static
6384{
6385 SCIP_NODEDATA* nodedatas;
6386
6387 nodedatas = (SCIP_NODEDATA*) dataptr;
6388 return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6389}
6390
6391
6392/** an overload was detected; initialized conflict analysis, add an initial reason
6393 *
6394 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6395 */
6396static
6398 SCIP* scip, /**< SCIP data structure */
6399 SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6400 int capacity, /**< cumulative capacity */
6401 int nleaves, /**< number of responsible leaves */
6402 int est, /**< earliest start time of the ...... */
6403 int lct, /**< latest completly time of the .... */
6404 int reportedenergy, /**< energy which already reported */
6405 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6406 int shift, /**< shift applied to all jobs before adding them to the tree */
6407 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6408 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6409 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6410 )
6411{
6412 SCIP_Longint energy;
6413 int j;
6414
6415 /* do nothing if conflict analysis is not applicable */
6417 return SCIP_OKAY;
6418
6419 SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6420
6421 /* compute energy of initial time window */
6422 energy = ((SCIP_Longint) lct - est) * capacity;
6423
6424 /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6425 SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6426
6427 /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6428 * thereby, compute the time window of interest
6429 */
6430 for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6431 {
6433
6435 assert(nodedata != NULL);
6436
6437 reportedenergy += computeEnergyContribution(leaves[j]);
6438
6439 /* adjust energy if the earliest start time decrease */
6440 if( nodedata->est < est )
6441 {
6442 est = nodedata->est;
6443 energy = ((SCIP_Longint) lct - est) * capacity;
6444 }
6445 }
6446 assert(reportedenergy > energy);
6447
6448 SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6449
6450 /* initialize conflict analysis */
6452
6453 /* flip earliest start time and latest completion time */
6454 if( !propest )
6455 {
6456 SCIPswapInts(&est, &lct);
6457
6458 /* shift earliest start time and latest completion time */
6459 lct = shift - lct;
6460 est = shift - est;
6461 }
6462 else
6463 {
6464 /* shift earliest start time and latest completion time */
6465 lct = lct + shift;
6466 est = est + shift;
6467 }
6468
6469 nleaves = j;
6470
6471 /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6472 * overloaded
6473 */
6474 for( j = nleaves-1; j >= 0; --j )
6475 {
6477
6479 assert(nodedata != NULL);
6480 assert(nodedata->var != NULL);
6481
6482 /* check if bound widening should be used */
6483 if( usebdwidening )
6484 {
6485 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6486 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6487 }
6488 else
6489 {
6492 }
6493
6494 if( explanation != NULL )
6495 explanation[nodedata->idx] = TRUE;
6496 }
6497
6498 (*initialized) = TRUE;
6499
6500 return SCIP_OKAY;
6501}
6502
6503/** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6504 * responsible interval bounds in *est_omega and *lct_omega
6505 */
6506static
6508 SCIP* scip, /**< SCIP data structure */
6509 int duration, /**< duration of the job to move */
6510 int demand, /**< demand of the job to move */
6511 int capacity, /**< cumulative capacity */
6512 int est, /**< earliest start time of the omega set */
6513 int lct, /**< latest start time of the omega set */
6514 int energy /**< energy of the omega set */
6515 )
6516{
6517 int newest;
6518
6519 newest = 0;
6520
6521 assert(scip != NULL);
6522
6523 if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6524 {
6525 if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6526 {
6527 newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6528 newest += est;
6529 }
6530 }
6531
6532 return newest;
6533}
6534
6535/** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6536 *
6537 * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6538 * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6539 */
6540static
6542 SCIP* scip, /**< SCIP data structure */
6543 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6544 SCIP_CONS* cons, /**< constraint which is propagated */
6545 SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6546 SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6547 int capacity, /**< cumulative capacity */
6548 int ncands, /**< number of candidates */
6549 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6550 int shift, /**< shift applied to all jobs before adding them to the tree */
6551 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6552 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6553 int* nchgbds, /**< pointer to store the number of bound changes */
6554 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6555 )
6556{
6557 SCIP_NODEDATA* rootdata;
6558 int j;
6559
6560 assert(!SCIPbtIsEmpty(tree));
6561
6562 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6563 assert(rootdata != NULL);
6564
6565 /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6566 for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6567 {
6569
6570 if( SCIPbtnodeIsRoot(leaves[j]) )
6571 break;
6572
6574 assert(nodedata->est != -1);
6575
6576 /* check if the root lambda envelop exeeds the available capacity */
6577 while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6578 {
6579 SCIP_BTNODE** omegaset;
6580 SCIP_BTNODE* leaf;
6581 SCIP_NODEDATA* leafdata;
6582 int nelements;
6583 int energy;
6584 int newest;
6585 int est;
6586 int lct;
6587
6588 assert(!(*cutoff));
6589
6590 /* find responsible leaf for the lambda envelope */
6592 assert(leaf != NULL);
6593 assert(SCIPbtnodeIsLeaf(leaf));
6594
6595 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6596 assert(leafdata != NULL);
6597 assert(!leafdata->intheta);
6598 assert(leafdata->duration > 0);
6599 assert(leafdata->est >= 0);
6600
6601 /* check if the job has to be removed since its latest completion is to large */
6602 if( leafdata->est + leafdata->duration >= nodedata->lct )
6603 {
6604 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6605
6606 /* the root might changed therefore we need to collect the new root node data */
6607 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6608 assert(rootdata != NULL);
6609
6610 continue;
6611 }
6612
6613 /* compute omega set */
6614 SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6615
6616 nelements = 0;
6617 est = INT_MAX;
6618 lct = INT_MIN;
6619 energy = 0;
6620
6621 /* collect the omega set from theta set */
6622 traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6623 assert(nelements > 0);
6624 assert(nelements < ncands);
6625
6626 newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6627
6628 /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6629 if( newest > lct )
6630 {
6631 SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6632
6633 /* analyze over load */
6634 SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6635 conshdlrdata->usebdwidening, initialized, explanation) );
6636 (*cutoff) = TRUE;
6637
6638 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6640 }
6641 else if( newest > 0 )
6642 {
6643 SCIP_Bool infeasible;
6644 SCIP_Bool tightened;
6645 INFERINFO inferinfo;
6646
6647 if( propest )
6648 {
6649 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6650 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6651
6652 SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6653 SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6654
6655 if( inferInfoIsValid(inferinfo) )
6656 {
6657 SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6658 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6659 }
6660 else
6661 {
6662 SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6663 TRUE, &infeasible, &tightened) );
6664 }
6665
6666 /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6668 }
6669 else
6670 {
6671 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6672 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6673
6674 SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6675 SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6676
6677 if( inferInfoIsValid(inferinfo) )
6678 {
6679 SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6680 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6681 }
6682 else
6683 {
6684 SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6685 TRUE, &infeasible, &tightened) );
6686 }
6687
6688 /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6690 }
6691
6692 /* adjust the earliest start time */
6693 if( tightened )
6694 {
6695 leafdata->est = newest;
6696 (*nchgbds)++;
6697 }
6698
6699 if( infeasible )
6700 {
6701 /* initialize conflict analysis if conflict analysis is applicable */
6703 {
6704 int i;
6705
6706 SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6707
6709
6710 /* add lower and upper bound of variable which leads to the infeasibilty */
6711 SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6712 SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6713
6714 if( explanation != NULL )
6715 explanation[leafdata->idx] = TRUE;
6716
6717 /* add lower and upper bound of variable which lead to the infeasibilty */
6718 for( i = 0; i < nelements; ++i )
6719 {
6720 nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6721 assert(nodedata != NULL);
6722
6725
6726 if( explanation != NULL )
6727 explanation[nodedata->idx] = TRUE;
6728 }
6729
6730 (*initialized) = TRUE;
6731 }
6732
6733 (*cutoff) = TRUE;
6734
6735 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6737 }
6738 }
6739
6740 /* free omegaset array */
6741 SCIPfreeBufferArray(scip, &omegaset);
6742
6743 /* delete responsible leaf from lambda */
6744 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6745
6746 /* the root might changed therefore we need to collect the new root node data */
6747 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6748 assert(rootdata != NULL);
6749 }
6750
6751 /* move current job j from the theta set into the lambda set */
6752 SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6753 }
6754
6755 return SCIP_OKAY;
6756}
6757
6758/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6759 *
6760 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6761 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6762 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6763 */
6764static
6766 SCIP* scip, /**< SCIP data structure */
6767 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6768 int nvars, /**< number of start time variables (activities) */
6769 SCIP_VAR** vars, /**< array of start time variables */
6770 int* durations, /**< array of durations */
6771 int* demands, /**< array of demands */
6772 int capacity, /**< cumulative capacity */
6773 int hmin, /**< left bound of time axis to be considered (including hmin) */
6774 int hmax, /**< right bound of time axis to be considered (not including hmax) */
6775 SCIP_CONS* cons, /**< constraint which is propagated */
6776 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6777 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6778 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6779 int* nchgbds, /**< pointer to store the number of bound changes */
6780 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6781 )
6782{
6783 SCIP_NODEDATA* nodedatas;
6784 SCIP_BTNODE** leaves;
6785 SCIP_BT* tree;
6786 int* nodedataidx;
6787
6788 int totalenergy;
6789 int nnodedatas;
6790 int ninsertcands;
6791 int ncands;
6792
6793 int shift;
6794 int idx = -1;
6795 int j;
6796
6797 assert(scip != NULL);
6798 assert(cons != NULL);
6799 assert(initialized != NULL);
6800 assert(cutoff != NULL);
6801 assert(*cutoff == FALSE);
6802
6803 SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6804
6805 SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6806 SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6807 SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6808
6809 ncands = 0;
6810 totalenergy = 0;
6811
6813
6814 /* compute the shift which we apply to compute .... latest completion time of all jobs */
6815 if( propest )
6816 shift = 0;
6817 else
6818 {
6819 shift = 0;
6820
6821 /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6822 * earliest start time propagation to handle the latest completion times
6823 */
6824 for( j = 0; j < nvars; ++j )
6825 {
6826 int lct;
6827
6828 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6829 shift = MAX(shift, lct);
6830 }
6831 }
6832
6833 /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6834 * horizon
6835 */
6836 for( j = 0; j < nvars; ++j )
6837 {
6839 SCIP_VAR* var;
6840 int duration;
6841 int leftadjust;
6842 int rightadjust;
6843 int energy;
6844 int est;
6845 int lct;
6846
6847 var = vars[j];
6848 assert(var != NULL);
6849
6850 duration = durations[j];
6851 assert(duration > 0);
6852
6853 leftadjust = 0;
6854 rightadjust = 0;
6855
6857 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6858
6859 /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6860 * effective horizon [hmin,hmax)
6861 */
6862 if( conshdlrdata->useadjustedjobs )
6863 {
6864 if( est < hmin )
6865 {
6866 leftadjust = (hmin - est);
6867 est = hmin;
6868 }
6869 if( lct > hmax )
6870 {
6871 rightadjust = (lct - hmax);
6872 lct = hmax;
6873 }
6874
6875 /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6876 * with the effective time horizon
6877 */
6878 if( duration - leftadjust - rightadjust <= 0 )
6879 continue;
6880 }
6881 else if( est < hmin || lct > hmax )
6882 continue;
6883
6884 energy = demands[j] * (duration - leftadjust - rightadjust);
6885 assert(energy > 0);
6886
6887 totalenergy += energy;
6888
6889 /* flip earliest start time and latest completion time */
6890 if( !propest )
6891 {
6892 SCIPswapInts(&est, &lct);
6893
6894 /* shift earliest start time and latest completion time */
6895 lct = shift - lct;
6896 est = shift - est;
6897 }
6898 else
6899 {
6900 /* shift earliest start time and latest completion time */
6901 lct = lct - shift;
6902 est = est - shift;
6903 }
6904 assert(est < lct);
6905 assert(est >= 0);
6906 assert(lct >= 0);
6907
6908 /* create search node data */
6909 nodedata = &nodedatas[ncands];
6910 nodedataidx[ncands] = ncands;
6911 ++ncands;
6912
6913 /* initialize search node data */
6914 /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6915 nodedata->key = est + j / (2.0 * nvars);
6916 nodedata->var = var;
6917 nodedata->est = est;
6918 nodedata->lct = lct;
6919 nodedata->demand = demands[j];
6920 nodedata->duration = duration;
6921 nodedata->leftadjust = leftadjust;
6922 nodedata->rightadjust = rightadjust;
6923
6924 /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6925 * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6926 * particular time interval [a,b] against the time interval [0,b].
6927 */
6928 nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
6929 nodedata->energytheta = energy;
6930 nodedata->enveloplambda = -1;
6931 nodedata->energylambda = -1;
6932
6933 nodedata->idx = j;
6934 nodedata->intheta = TRUE;
6935 }
6936
6937 nnodedatas = ncands;
6938
6939 /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6940 SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
6941
6942 ninsertcands = 0;
6943
6944 /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6945 * the root envelop detects an overload
6946 */
6947 for( j = 0; j < ncands; ++j )
6948 {
6949 SCIP_BTNODE* leaf;
6950 SCIP_NODEDATA* rootdata;
6951
6952 idx = nodedataidx[j];
6953
6954 /* check if the new job opens a time window which size is so large that it offers more energy than the total
6955 * energy of all candidate jobs. If so we skip that one.
6956 */
6957 if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
6958 {
6959 /* set the earliest start time to minus one to mark that candidate to be not used */
6960 nodedatas[idx].est = -1;
6961 continue;
6962 }
6963
6964 /* create search node */
6965 SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
6966
6967 /* insert new node into the theta set and updete the envelops */
6968 SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
6969 assert(nnodedatas <= 2*nvars);
6970
6971 /* move the inserted candidates together */
6972 leaves[ninsertcands] = leaf;
6973 ninsertcands++;
6974
6975 assert(!SCIPbtIsEmpty(tree));
6976 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6977 assert(rootdata != NULL);
6978
6979 /* check if the theta set envelops exceeds the available capacity */
6980 if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
6981 {
6982 SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
6983 (*cutoff) = TRUE;
6984
6985 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6987
6988 break;
6989 }
6990 }
6991
6992 /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
6993 if( *cutoff )
6994 {
6995 int glbenery;
6996 int est;
6997 int lct;
6998
6999 glbenery = 0;
7000 assert( 0 <= idx );
7001 est = nodedatas[idx].est;
7002 lct = nodedatas[idx].lct;
7003
7004 /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7005 * which led to an overload
7006 */
7007 for( j = j+1; j < ncands; ++j )
7008 {
7010 int duration;
7011 int glbest;
7012 int glblct;
7013
7014 idx = nodedataidx[j];
7015 nodedata = &nodedatas[idx];
7016 assert(nodedata != NULL);
7017
7018 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7019
7020 /* get latest start time */
7022 glblct = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7023
7024 /* check if parts of the jobs run with the time window defined by the last inserted job */
7025 if( glbest < est )
7026 duration -= (est - glbest);
7027
7028 if( glblct > lct )
7029 duration -= (glblct - lct);
7030
7031 if( duration > 0 )
7032 {
7033 glbenery += nodedata->demand * duration;
7034
7035 if( explanation != NULL )
7036 explanation[nodedata->idx] = TRUE;
7037 }
7038 }
7039
7040 /* analyze the overload */
7041 SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7042 conshdlrdata->usebdwidening, initialized, explanation) );
7043 }
7044 else if( ninsertcands > 1 && conshdlrdata->efinfer )
7045 {
7046 /* if we have more than one job insterted and edge-finding should be performed we do it */
7047 SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7048 propest, shift, initialized, explanation, nchgbds, cutoff) );
7049 }
7050
7051 /* free theta tree */
7052 SCIPbtFree(&tree);
7053
7054 /* free buffer arrays */
7055 SCIPfreeBufferArray(scip, &leaves);
7056 SCIPfreeBufferArray(scip, &nodedataidx);
7057 SCIPfreeBufferArray(scip, &nodedatas);
7058
7059 return SCIP_OKAY;
7060}
7061
7062/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7063 *
7064 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7065 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7066 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7067 */
7068static
7070 SCIP* scip, /**< SCIP data structure */
7071 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7072 int nvars, /**< number of start time variables (activities) */
7073 SCIP_VAR** vars, /**< array of start time variables */
7074 int* durations, /**< array of durations */
7075 int* demands, /**< array of demands */
7076 int capacity, /**< cumulative capacity */
7077 int hmin, /**< left bound of time axis to be considered (including hmin) */
7078 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7079 SCIP_CONS* cons, /**< constraint which is propagated */
7080 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7081 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7082 int* nchgbds, /**< pointer to store the number of bound changes */
7083 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7084 )
7085{
7086 /* check if a cutoff was already detected */
7087 if( (*cutoff) )
7088 return SCIP_OKAY;
7089
7090 /* check if at least the basic overload checking should be preformed */
7091 if( !conshdlrdata->efcheck )
7092 return SCIP_OKAY;
7093
7094 /* check for overload, which may result in a cutoff */
7095 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7096 cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7097
7098 /* check if a cutoff was detected */
7099 if( (*cutoff) )
7100 return SCIP_OKAY;
7101
7102 /* check if bound should be infer */
7103 if( !conshdlrdata->efinfer )
7104 return SCIP_OKAY;
7105
7106 /* check for overload, which may result in a cutoff */
7107 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7108 cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7109
7110 return SCIP_OKAY;
7111}
7112
7113/** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7114 * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7115 * event points
7116 */
7117static
7119 SCIP* scip, /**< SCIP data structure */
7120 int nvars, /**< number of start time variables (activities) */
7121 SCIP_VAR** vars, /**< array of start time variables */
7122 int* durations, /**< array of durations */
7123 int* demands, /**< array of demands */
7124 int capacity, /**< cumulative capacity */
7125 int hmin, /**< left bound of time axis to be considered (including hmin) */
7126 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7127 SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7128 )
7129{
7130 SCIP_VAR* var;
7131 int* starttimes; /* stores when each job is starting */
7132 int* endtimes; /* stores when each job ends */
7133 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7134 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7135
7136 int lb;
7137 int ub;
7138 int freecapacity; /* remaining capacity */
7139 int curtime; /* point in time which we are just checking */
7140 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7141 int njobs;
7142 int j;
7143
7144 assert(scip != NULL);
7145 assert(redundant != NULL);
7146
7147 (*redundant) = TRUE;
7148
7149 /* if no activities are associated with this cumulative then this constraint is redundant */
7150 if( nvars == 0 )
7151 return SCIP_OKAY;
7152
7153 assert(vars != NULL);
7154
7155 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7156 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7157 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7158 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7159
7160 njobs = 0;
7161
7162 /* assign variables, start and endpoints to arrays */
7163 for( j = 0; j < nvars; ++j )
7164 {
7165 assert(durations[j] > 0);
7166 assert(demands[j] > 0);
7167
7168 var = vars[j];
7169 assert(var != NULL);
7170
7173
7174 /* check if jobs runs completely outside of the effective time horizon */
7175 if( lb >= hmax || ub <= hmin - durations[j] )
7176 continue;
7177
7178 starttimes[njobs] = MAX(lb, hmin);
7179 startindices[njobs] = j;
7180
7181 endtimes[njobs] = MIN(ub == INT_MAX ? ub : ub + durations[j], hmax);
7182 endindices[njobs] = j;
7183 assert(starttimes[njobs] <= endtimes[njobs]);
7184 njobs++;
7185 }
7186
7187 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7188 SCIPsortIntInt(starttimes, startindices, njobs);
7189 SCIPsortIntInt(endtimes, endindices, njobs);
7190
7191 endindex = 0;
7192 freecapacity = capacity;
7193
7194 /* check each start point of a job whether the capacity is violated or not */
7195 for( j = 0; j < njobs; ++j )
7196 {
7197 curtime = starttimes[j];
7198
7199 /* stop checking, if time point is above hmax */
7200 if( curtime >= hmax )
7201 break;
7202
7203 /* subtract all capacity needed up to this point */
7204 freecapacity -= demands[startindices[j]];
7205 while( j+1 < njobs && starttimes[j+1] == curtime )
7206 {
7207 ++j;
7208 freecapacity -= demands[startindices[j]];
7209 }
7210
7211 /* free all capacity usages of jobs the are no longer running */
7212 while( endtimes[endindex] <= curtime )
7213 {
7214 freecapacity += demands[endindices[endindex]];
7215 ++endindex;
7216 }
7217 assert(freecapacity <= capacity);
7218
7219 /* check freecapacity to be smaller than zero */
7220 if( freecapacity < 0 && curtime >= hmin )
7221 {
7222 (*redundant) = FALSE;
7223 break;
7224 }
7225 } /*lint --e{850}*/
7226
7227 /* free all buffer arrays */
7228 SCIPfreeBufferArray(scip, &endindices);
7229 SCIPfreeBufferArray(scip, &startindices);
7230 SCIPfreeBufferArray(scip, &endtimes);
7231 SCIPfreeBufferArray(scip, &starttimes);
7232
7233 return SCIP_OKAY;
7234}
7235
7236/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7237 * completion time
7238 */
7239static
7241 SCIP* scip, /**< SCIP data structure */
7242 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7243 SCIP_PROFILE* profile, /**< resource profile */
7244 int nvars, /**< number of variables (jobs) */
7245 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7246 int* durations, /**< array containing corresponding durations */
7247 int* demands, /**< array containing corresponding demands */
7248 int capacity, /**< cumulative capacity */
7249 int hmin, /**< left bound of time axis to be considered (including hmin) */
7250 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7251 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7252 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7253 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7254 )
7255{
7256 int v;
7257
7258 /* insert all cores */
7259 for( v = 0; v < nvars; ++v )
7260 {
7261 SCIP_VAR* var;
7262 SCIP_Bool infeasible;
7263 int duration;
7264 int demand;
7265 int begin;
7266 int end;
7267 int est;
7268 int lst;
7269 int pos;
7270
7271 var = vars[v];
7272 assert(var != NULL);
7275
7276 duration = durations[v];
7277 assert(duration > 0);
7278
7279 demand = demands[v];
7280 assert(demand > 0);
7281
7282 /* collect earliest and latest start time */
7285
7286 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7287 if( lst + duration <= hmin || est >= hmax )
7288 continue;
7289
7290 /* compute core interval w.r.t. effective time horizon */
7291 begin = MAX(hmin, lst);
7292 end = MIN(hmax, est + duration);
7293
7294 /* check if a core exists */
7295 if( begin >= end )
7296 continue;
7297
7298 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7299 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7300
7301 /* insert the core into core resource profile (complexity O(log n)) */
7302 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7303
7304 /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7305 if( infeasible )
7306 {
7307 assert(begin <= SCIPprofileGetTime(profile, pos));
7308 assert(end > SCIPprofileGetTime(profile, pos));
7309
7310 /* use conflict analysis to analysis the core insertion which was infeasible */
7311 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7312 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7313
7314 if( explanation != NULL )
7315 explanation[v] = TRUE;
7316
7317 (*cutoff) = TRUE;
7318
7319 /* for the statistic we count the number of times a cutoff was detected due the time-time */
7321
7322 break;
7323 }
7324 }
7325
7326 return SCIP_OKAY;
7327}
7328
7329/** propagate the cumulative condition */
7330static
7332 SCIP* scip, /**< SCIP data structure */
7333 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7334 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7335 int nvars, /**< number of start time variables (activities) */
7336 SCIP_VAR** vars, /**< array of start time variables */
7337 int* durations, /**< array of durations */
7338 int* demands, /**< array of demands */
7339 int capacity, /**< cumulative capacity */
7340 int hmin, /**< left bound of time axis to be considered (including hmin) */
7341 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7342 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7343 int* nchgbds, /**< pointer to store the number of bound changes */
7344 SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7345 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7346 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7347 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7348 )
7349{
7350 SCIP_PROFILE* profile;
7351
7352 SCIP_RETCODE retcode = SCIP_OKAY;
7353
7354 assert(nchgbds != NULL);
7355 assert(initialized != NULL);
7356 assert(cutoff != NULL);
7357 assert(!(*cutoff));
7358
7359 /**@todo avoid always sorting the variable array */
7360
7361 /* check if the constraint is redundant */
7362 SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7363
7364 if( *redundant )
7365 return SCIP_OKAY;
7366
7367 /* create an empty resource profile for profiling the cores of the jobs */
7368 SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7369
7370 /* create core profile (compulsory parts) */
7371 SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7372 initialized, explanation, cutoff), TERMINATE );
7373
7374 /* propagate the job cores until nothing else can be detected */
7375 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7376 {
7377 SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7378 nchgbds, initialized, explanation, cutoff), TERMINATE );
7379 }
7380
7381 /* run edge finding propagator */
7382 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7383 {
7384 SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7385 cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7386 }
7387
7388 /* run time-table edge-finding propagator */
7389 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7390 {
7391 SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7392 nchgbds, initialized, explanation, cutoff), TERMINATE );
7393 }
7394 /* free resource profile */
7395TERMINATE:
7396 SCIPprofileFree(&profile);
7397
7398 return retcode;
7399}
7400
7401/** propagate the cumulative constraint */
7402static
7404 SCIP* scip, /**< SCIP data structure */
7405 SCIP_CONS* cons, /**< constraint to propagate */
7406 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7407 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7408 int* nchgbds, /**< pointer to store the number of bound changes */
7409 int* ndelconss, /**< pointer to store the number of deleted constraints */
7410 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7411 )
7412{
7413 SCIP_CONSDATA* consdata;
7414 SCIP_Bool initialized;
7415 SCIP_Bool redundant;
7416 int oldnchgbds;
7417
7418 assert(scip != NULL);
7419 assert(cons != NULL);
7420
7421 consdata = SCIPconsGetData(cons);
7422 assert(consdata != NULL);
7423
7424 oldnchgbds = *nchgbds;
7425 initialized = FALSE;
7426 redundant = FALSE;
7427
7428 if( SCIPconsIsDeleted(cons) )
7429 {
7430 assert(SCIPinProbing(scip));
7431 return SCIP_OKAY;
7432 }
7433
7434 /* if the constraint marked to be propagated, do nothing */
7435 if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7436 return SCIP_OKAY;
7437
7438 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7439 consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7440 consdata->hmin, consdata->hmax, cons,
7441 nchgbds, &redundant, &initialized, NULL, cutoff) );
7442
7443 if( redundant )
7444 {
7445 SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7446 SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7447
7448 if( !SCIPinProbing(scip) )
7449 {
7451 (*ndelconss)++;
7452 }
7453 }
7454 else
7455 {
7456 if( initialized )
7457 {
7458 /* run conflict analysis since it was initialized */
7459 assert(*cutoff == TRUE);
7460 SCIPdebugMsg(scip, "start conflict analysis\n");
7462 }
7463
7464 /* if successful, reset age of constraint */
7465 if( *cutoff || *nchgbds > oldnchgbds )
7466 {
7468 }
7469 else
7470 {
7471 /* mark the constraint to be propagated */
7472 consdata->propagated = TRUE;
7473 }
7474 }
7475
7476 return SCIP_OKAY;
7477}
7478
7479/** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7480 * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7481 * be realize as domain reduction. Otherwise we do nothing
7482 */
7483static
7485 SCIP* scip, /**< SCIP data structure */
7486 SCIP_VAR** vars, /**< problem variables */
7487 int nvars, /**< number of problem variables */
7488 int probingpos, /**< variable number to apply probing on */
7489 SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7490 SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7491 SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7492 SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7493 SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7494 SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7495 SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7496 SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7497 SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7498 SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7499 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7500 SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7501 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7502 )
7503{
7504 SCIP_VAR* var;
7505 SCIP_Bool tightened;
7506
7507 assert(probingpos >= 0);
7508 assert(probingpos < nvars);
7509 assert(success != NULL);
7510 assert(cutoff != NULL);
7511
7512 var = vars[probingpos];
7513 assert(var != NULL);
7514 assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7515 assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7516 assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7517 assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7518
7519 (*success) = FALSE;
7520
7522 return SCIP_OKAY;
7523
7524 /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7525 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7526 leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7527
7528 if( (*cutoff) )
7529 {
7530 /* note that cutoff may occur if presolving has not been executed fully */
7531 SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7532
7533 if( tightened )
7534 {
7535 (*success) =TRUE;
7536 (*nfixedvars)++;
7537 }
7538
7539 return SCIP_OKAY;
7540 }
7541
7542 /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7543 * presolving has not been executed fully
7544 */
7545 if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7546 {
7547 /* note that cutoff may occur if presolving has not been executed fully */
7548 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7549
7550 if( tightened )
7551 {
7552 (*success) = TRUE;
7553 (*nfixedvars)++;
7554 }
7555
7556 return SCIP_OKAY;
7557 }
7558
7559 /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7560 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7561 rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7562
7563 if( (*cutoff) )
7564 {
7565 /* note that cutoff may occur if presolving has not been executed fully */
7566 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7567
7568 if( tightened )
7569 {
7570 (*success) =TRUE;
7571 (*nfixedvars)++;
7572 }
7573
7574 return SCIP_OKAY;
7575 }
7576
7577 return SCIP_OKAY;
7578}
7579
7580/** is it possible, to round variable down w.r.t. objective function */
7581static
7583 SCIP* scip, /**< SCIP data structure */
7584 SCIP_VAR* var, /**< problem variable */
7585 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7586 )
7587{
7588 SCIP_Real objval;
7589 int scalar;
7590
7591 assert(roundable != NULL);
7592
7593 *roundable = TRUE;
7594
7595 /* a fixed variable can be definition always be safely rounded */
7597 return SCIP_OKAY;
7598
7599 /* in case the variable is not active we need to check the object coefficient of the active variable */
7600 if( !SCIPvarIsActive(var) )
7601 {
7602 SCIP_VAR* actvar;
7603 int constant;
7604
7605 actvar = var;
7606
7607 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7608 assert(scalar != 0);
7609
7610 objval = scalar * SCIPvarGetObj(actvar);
7611 } /*lint !e438*/
7612 else
7613 {
7614 scalar = 1;
7615 objval = SCIPvarGetObj(var);
7616 }
7617
7618 /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7619 * (the transformed problem is always a minimization problem)
7620 *
7621 * @note that we need to check this condition w.r.t. active variable space
7622 */
7623 if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7624 *roundable = FALSE;
7625
7626 return SCIP_OKAY;
7627}
7628
7629/** is it possible, to round variable up w.r.t. objective function */
7630static
7632 SCIP* scip, /**< SCIP data structure */
7633 SCIP_VAR* var, /**< problem variable */
7634 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7635 )
7636{
7637 SCIP_Real objval;
7638 int scalar;
7639
7640 assert(roundable != NULL);
7641
7642 *roundable = TRUE;
7643
7644 /* a fixed variable can be definition always be safely rounded */
7646 return SCIP_OKAY;
7647
7648 /* in case the variable is not active we need to check the object coefficient of the active variable */
7649 if( !SCIPvarIsActive(var) )
7650 {
7651 SCIP_VAR* actvar;
7652 int constant;
7653
7654 actvar = var;
7655
7656 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7657 assert(scalar != 0);
7658
7659 objval = scalar * SCIPvarGetObj(actvar);
7660 } /*lint !e438*/
7661 else
7662 {
7663 scalar = 1;
7664 objval = SCIPvarGetObj(var);
7665 }
7666
7667 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7668 * (the transformed problem is always a minimization problem)
7669 *
7670 * @note that we need to check this condition w.r.t. active variable space
7671 */
7672 if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7673 *roundable = FALSE;
7674
7675 return SCIP_OKAY;
7676}
7677
7678/** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7679 * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7680 * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7681 * the only one locking this variable in the corresponding direction.
7682 */
7683static
7685 SCIP* scip, /**< SCIP data structure */
7686 SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7687 int nconss, /**< number of cumulative constraints */
7688 SCIP_Bool local, /**< use local bounds effective horizon? */
7689 int* alternativelbs, /**< alternative lower bounds */
7690 int* alternativeubs, /**< alternative lower bounds */
7691 int* downlocks, /**< number of constraints with down lock participating by the computation */
7692 int* uplocks /**< number of constraints with up lock participating by the computation */
7693 )
7694{
7695 int nvars;
7696 int c;
7697 int v;
7698
7699 for( c = 0; c < nconss; ++c )
7700 {
7701 SCIP_CONSDATA* consdata;
7702 SCIP_CONS* cons;
7703 SCIP_VAR* var;
7704 int hmin;
7705 int hmax;
7706
7707 cons = conss[c];
7708 assert(cons != NULL);
7709
7710 /* ignore constraints which are already deletet and those which are not check constraints */
7711 if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7712 continue;
7713
7714 consdata = SCIPconsGetData(cons);
7715 assert(consdata != NULL);
7716 assert(consdata->nvars > 1);
7717
7718 /* compute the hmin and hmax */
7719 if( local )
7720 {
7721 SCIP_PROFILE* profile;
7722 SCIP_RETCODE retcode;
7723
7724 /* create empty resource profile with infinity resource capacity */
7725 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7726
7727 /* create worst case resource profile */
7728 retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7729
7730 hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7731 hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7732
7733 /* free worst case profile */
7734 SCIPprofileFree(&profile);
7735
7736 if( retcode != SCIP_OKAY )
7737 return retcode;
7738 }
7739 else
7740 {
7741 hmin = consdata->hmin;
7742 hmax = consdata->hmax;
7743 }
7744
7745 consdata = SCIPconsGetData(cons);
7746 assert(consdata != NULL);
7747
7748 nvars = consdata->nvars;
7749
7750 for( v = 0; v < nvars; ++v )
7751 {
7752 int scalar;
7753 int constant;
7754 int idx;
7755
7756 var = consdata->vars[v];
7757 assert(var != NULL);
7758
7759 /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7761
7762 /* ignore variable locally fixed variables */
7763 if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7764 continue;
7765
7766 SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7767 idx = SCIPvarGetProbindex(var);
7768 assert(idx >= 0);
7769
7770 /* first check lower bound fixing */
7771 if( consdata->downlocks[v] )
7772 {
7773 int ect;
7774 int est;
7775
7776 /* the variable has a down locked */
7777 est = scalar * boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7778 ect = est + consdata->durations[v];
7779
7780 if( ect <= hmin || hmin >= hmax )
7781 downlocks[idx]++;
7782 else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7783 {
7784 alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7785 downlocks[idx]++;
7786 }
7787 }
7788
7789 /* second check upper bound fixing */
7790 if( consdata->uplocks[v] )
7791 {
7792 int duration;
7793 int lct;
7794 int lst;
7795
7796 duration = consdata->durations[v];
7797
7798 /* the variable has a up lock locked */
7799 lst = scalar * boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7800 lct = lst + duration;
7801
7802 if( lst >= hmax || hmin >= hmax )
7803 uplocks[idx]++;
7804 else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7805 {
7806 alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7807 uplocks[idx]++;
7808 }
7809 }
7810 }
7811 }
7812
7813 return SCIP_OKAY;
7814}
7815
7816/** apply all fixings which are given by the alternative bounds */
7817static
7819 SCIP* scip, /**< SCIP data structure */
7820 SCIP_VAR** vars, /**< array of active variables */
7821 int nvars, /**< number of active variables */
7822 int* alternativelbs, /**< alternative lower bounds */
7823 int* alternativeubs, /**< alternative lower bounds */
7824 int* downlocks, /**< number of constraints with down lock participating by the computation */
7825 int* uplocks, /**< number of constraints with up lock participating by the computation */
7826 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7827 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7828 )
7829{
7830 SCIP_Real* downimpllbs;
7831 SCIP_Real* downimplubs;
7832 SCIP_Real* downproplbs;
7833 SCIP_Real* downpropubs;
7834 SCIP_Real* upimpllbs;
7835 SCIP_Real* upimplubs;
7836 SCIP_Real* upproplbs;
7837 SCIP_Real* uppropubs;
7838 int v;
7839
7840 /* get temporary memory for storing probing results */
7841 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7842 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7843 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7844 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7845 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7846 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7847 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7848 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7849
7850 for( v = 0; v < nvars; ++v )
7851 {
7852 SCIP_VAR* var;
7853 SCIP_Bool infeasible;
7854 SCIP_Bool fixed;
7855 SCIP_Bool roundable;
7856 int ub;
7857 int lb;
7858
7859 var = vars[v];
7860 assert(var != NULL);
7861
7862 /* ignore variables for which no alternative bounds have been computed */
7863 if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7864 continue;
7865
7868
7869 /* ignore fixed variables */
7870 if( ub - lb <= 0 )
7871 continue;
7872
7873 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7874 {
7875 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7876
7877 if( roundable )
7878 {
7879 if( alternativelbs[v] > ub )
7880 {
7881 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7882 assert(!infeasible);
7883 assert(fixed);
7884
7885 (*nfixedvars)++;
7886
7887 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7888 * constraints
7889 */
7891 }
7892 else
7893 {
7894 SCIP_Bool success;
7895
7896 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7897 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7898 * infeasible we can apply the dual reduction; otherwise we do nothing
7899 */
7900 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7901 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7902 nfixedvars, &success, cutoff) );
7903
7904 if( success )
7905 {
7907 }
7908 }
7909 }
7910 }
7911
7914
7915 /* ignore fixed variables */
7916 if( ub - lb <= 0 )
7917 continue;
7918
7919 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7920 {
7921 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7922
7923 if( roundable )
7924 {
7925 if( alternativeubs[v] < lb )
7926 {
7927 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7928 assert(!infeasible);
7929 assert(fixed);
7930
7931 (*nfixedvars)++;
7932
7933 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7934 * constraints
7935 */
7937 }
7938 else
7939 {
7940 SCIP_Bool success;
7941
7942 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7943 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7944 * infeasible we can apply the dual reduction; otherwise we do nothing
7945 */
7946 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7947 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7948 nfixedvars, &success, cutoff) );
7949
7950 if( success )
7951 {
7953 }
7954 }
7955 }
7956 }
7957 }
7958
7959 /* free temporary memory */
7960 SCIPfreeBufferArray(scip, &uppropubs);
7961 SCIPfreeBufferArray(scip, &upproplbs);
7962 SCIPfreeBufferArray(scip, &upimplubs);
7963 SCIPfreeBufferArray(scip, &upimpllbs);
7964 SCIPfreeBufferArray(scip, &downpropubs);
7965 SCIPfreeBufferArray(scip, &downproplbs);
7966 SCIPfreeBufferArray(scip, &downimplubs);
7967 SCIPfreeBufferArray(scip, &downimpllbs);
7968
7969 return SCIP_OKAY;
7970}
7971
7972/** propagate all constraints together */
7973static
7975 SCIP* scip, /**< SCIP data structure */
7976 SCIP_CONS** conss, /**< all cumulative constraint */
7977 int nconss, /**< number of cumulative constraints */
7978 SCIP_Bool local, /**< use local bounds effective horizon? */
7979 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7980 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7981 SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7982 )
7983{ /*lint --e{715}*/
7984 SCIP_VAR** vars;
7985 int* downlocks;
7986 int* uplocks;
7987 int* alternativelbs;
7988 int* alternativeubs;
7989 int oldnfixedvars;
7990 int nvars;
7991 int v;
7992
7994 return SCIP_OKAY;
7995
7996 nvars = SCIPgetNVars(scip);
7997 oldnfixedvars = *nfixedvars;
7998
7999 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8000 SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8001 SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8002 SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8003 SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8004
8005 /* initialize arrays */
8006 for( v = 0; v < nvars; ++v )
8007 {
8008 downlocks[v] = 0;
8009 uplocks[v] = 0;
8010 alternativelbs[v] = INT_MAX;
8011 alternativeubs[v] = INT_MIN;
8012 }
8013
8014 /* compute alternative bounds */
8015 SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8016
8017 /* apply fixing which result of the alternative bounds directly */
8018 SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8019 nfixedvars, cutoff) );
8020
8021 if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8022 {
8023 SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8024 }
8025
8026 /* free all buffers */
8027 SCIPfreeBufferArray(scip, &alternativeubs);
8028 SCIPfreeBufferArray(scip, &alternativelbs);
8029 SCIPfreeBufferArray(scip, &uplocks);
8030 SCIPfreeBufferArray(scip, &downlocks);
8031 SCIPfreeBufferArray(scip, &vars);
8032
8033 return SCIP_OKAY;
8034}
8035
8036/**@} */
8037
8038/**@name Linear relaxations
8039 *
8040 * @{
8041 */
8042
8043/** creates covering cuts for jobs violating resource constraints */
8044static
8046 SCIP* scip, /**< SCIP data structure */
8047 SCIP_CONS* cons, /**< constraint to be checked */
8048 int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8049 int time /**< at this point in time covering constraints are valid */
8050 )
8051{
8052 SCIP_CONSDATA* consdata;
8053 SCIP_ROW* row;
8054 int* flexibleids;
8055 int* demands;
8056
8057 char rowname[SCIP_MAXSTRLEN];
8058
8059 int remainingcap;
8060 int smallcoversize; /* size of a small cover */
8061 int bigcoversize; /* size of a big cover */
8062 int nvars;
8063
8064 int nflexible;
8065 int sumdemand; /* demand of all jobs up to a certain index */
8066 int j;
8067
8068 assert(cons != NULL);
8069
8070 /* get constraint data structure */
8071 consdata = SCIPconsGetData(cons);
8072 assert(consdata != NULL );
8073
8074 nvars = consdata->nvars;
8075
8076 /* sort jobs according to demands */
8077 SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8078 SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8079
8080 nflexible = 0;
8081 remainingcap = consdata->capacity;
8082
8083 /* get all jobs intersecting point 'time' with their bounds */
8084 for( j = 0; j < nvars; ++j )
8085 {
8086 int ub;
8087
8088 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8089
8090 /* only add jobs to array if they intersect with point 'time' */
8091 if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8092 {
8093 /* if job is fixed, capacity has to be decreased */
8094 if( startvalues[j] == ub )
8095 {
8096 remainingcap -= consdata->demands[j];
8097 }
8098 else
8099 {
8100 demands[nflexible] = consdata->demands[j];
8101 flexibleids[nflexible] = j;
8102 ++nflexible;
8103 }
8104 }
8105 }
8106 assert(remainingcap >= 0);
8107
8108 /* sort demands and job ids */
8109 SCIPsortIntInt(demands, flexibleids, nflexible);
8110
8111 /*
8112 * version 1:
8113 * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8114 * erzeuge cover constraint
8115 *
8116 */
8117
8118 /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8119 sumdemand = 0;
8120 j = 0;
8121
8122 while( j < nflexible && sumdemand <= remainingcap )
8123 {
8124 sumdemand += demands[j];
8125 j++;
8126 }
8127
8128 /* j jobs form a conflict, set coversize to 'j - 1' */
8129 bigcoversize = j-1;
8130 assert(sumdemand > remainingcap);
8131 assert(bigcoversize < nflexible);
8132
8133 /* - create a row for all jobs and their binary variables.
8134 * - at most coversize many binary variables of jobs can be set to one
8135 */
8136
8137 /* construct row name */
8138 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8139 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8140 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8142
8143 for( j = 0; j < nflexible; ++j )
8144 {
8145 SCIP_VAR** binvars;
8146 SCIP_Real* vals;
8147 int nbinvars;
8148 int idx;
8149 int start;
8150 int end;
8151 int lb;
8152 int ub;
8153 int b;
8154
8155 idx = flexibleids[j];
8156
8157 /* get and add binvars into var array */
8158 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8159 assert(nbinvars != 0);
8160
8161 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8162 assert(vals != NULL);
8163
8164 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8165 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8166
8167 /* compute start and finishing time */
8168 start = time - consdata->durations[idx] + 1;
8169 end = MIN(time, ub);
8170
8171 /* add all neccessary binary variables */
8172 for( b = 0; b < nbinvars; ++b )
8173 {
8174 if( vals[b] < start || vals[b] < lb )
8175 continue;
8176
8177 if( vals[b] > end )
8178 break;
8179
8180 assert(binvars[b] != NULL);
8181 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8182 }
8183 }
8184
8185 /* insert and release row */
8187
8188 if( consdata->bcoverrowssize == 0 )
8189 {
8190 consdata->bcoverrowssize = 10;
8191 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8192 }
8193 if( consdata->nbcoverrows == consdata->bcoverrowssize )
8194 {
8195 consdata->bcoverrowssize *= 2;
8196 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8197 }
8198
8199 consdata->bcoverrows[consdata->nbcoverrows] = row;
8200 consdata->nbcoverrows++;
8201
8202 /*
8203 * version 2:
8204 * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8205 * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8206 */
8207 /* find maximum number of jobs that can run in parallel (= coversize -1) */
8208 sumdemand = 0;
8209 j = nflexible -1;
8210 while( sumdemand <= remainingcap )
8211 {
8212 assert(j >= 0);
8213 sumdemand += demands[j];
8214 j--;
8215 }
8216
8217 smallcoversize = nflexible - (j + 1) - 1;
8218 while( j > 0 && demands[j] == demands[nflexible-1] )
8219 --j;
8220
8221 assert(smallcoversize < nflexible);
8222
8223 if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8224 {
8225 /* construct row name */
8226 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8227 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8228 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8230
8231 /* filter binary variables for each unfixed job */
8232 for( j = j + 1; j < nflexible; ++j )
8233 {
8234 SCIP_VAR** binvars;
8235 SCIP_Real* vals;
8236 int nbinvars;
8237 int idx;
8238 int start;
8239 int end;
8240 int lb;
8241 int ub;
8242 int b;
8243
8244 idx = flexibleids[j];
8245
8246 /* get and add binvars into var array */
8247 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8248 assert(nbinvars != 0);
8249
8250 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8251 assert(vals != NULL);
8252
8253 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8254 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8255
8256 /* compute start and finishing time */
8257 start = time - consdata->durations[idx] + 1;
8258 end = MIN(time, ub);
8259
8260 /* add all neccessary binary variables */
8261 for( b = 0; b < nbinvars; ++b )
8262 {
8263 if( vals[b] < start || vals[b] < lb )
8264 continue;
8265
8266 if( vals[b] > end )
8267 break;
8268
8269 assert(binvars[b] != NULL);
8270 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8271 }
8272 }
8273
8274 /* insert and release row */
8276 if( consdata->scoverrowssize == 0 )
8277 {
8278 consdata->scoverrowssize = 10;
8279 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8280 }
8281 if( consdata->nscoverrows == consdata->scoverrowssize )
8282 {
8283 consdata->scoverrowssize *= 2;
8284 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8285 }
8286
8287 consdata->scoverrows[consdata->nscoverrows] = row;
8288 consdata->nscoverrows++;
8289 }
8290
8291 /* free buffer arrays */
8292 SCIPfreeBufferArray(scip, &flexibleids);
8293 SCIPfreeBufferArray(scip, &demands);
8294
8295 return SCIP_OKAY;
8296}
8297
8298/** method to construct cover cuts for all points in time */
8299static
8301 SCIP* scip, /**< SCIP data structure */
8302 SCIP_CONS* cons /**< constraint to be separated */
8303 )
8304{
8305 SCIP_CONSDATA* consdata;
8306
8307 int* startvalues; /* stores when each job is starting */
8308 int* endvalues; /* stores when each job ends */
8309 int* startvaluessorted; /* stores when each job is starting */
8310 int* endvaluessorted; /* stores when each job ends */
8311 int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8312 int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8313
8314 int nvars; /* number of jobs for this constraint */
8315 int freecapacity; /* remaining capacity */
8316 int curtime; /* point in time which we are just checking */
8317 int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8318
8319 int hmin;
8320 int hmax;
8321
8322 int j;
8323 int t;
8324
8325 assert(scip != NULL);
8326 assert(cons != NULL);
8327
8328 consdata = SCIPconsGetData(cons);
8329 assert(consdata != NULL);
8330
8331 /* if no activities are associated with this resource then this constraint is redundant */
8332 if( consdata->vars == NULL )
8333 return SCIP_OKAY;
8334
8335 nvars = consdata->nvars;
8336 hmin = consdata->hmin;
8337 hmax = consdata->hmax;
8338
8339 SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8340 SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8341 SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8342 SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8343 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8344 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8345
8346 /* assign start and endpoints to arrays */
8347 for ( j = 0; j < nvars; ++j )
8348 {
8349 startvalues[j] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8350 startvaluessorted[j] = startvalues[j];
8351
8352 endvalues[j] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8353 endvaluessorted[j] = endvalues[j];
8354
8355 startindices[j] = j;
8356 endindices[j] = j;
8357 }
8358
8359 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8360 * (and sort the indices in the same way) */
8361 SCIPsortIntInt(startvaluessorted, startindices, nvars);
8362 SCIPsortIntInt(endvaluessorted, endindices, nvars);
8363
8364 endidx = 0;
8365 freecapacity = consdata->capacity;
8366
8367 /* check each startpoint of a job whether the capacity is kept or not */
8368 for( j = 0; j < nvars; ++j )
8369 {
8370 curtime = startvaluessorted[j];
8371 if( curtime >= hmax )
8372 break;
8373
8374 /* subtract all capacity needed up to this point */
8375 freecapacity -= consdata->demands[startindices[j]];
8376
8377 while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8378 {
8379 ++j;
8380 freecapacity -= consdata->demands[startindices[j]];
8381 }
8382
8383 /* free all capacity usages of jobs the are no longer running */
8384 while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8385 {
8386 freecapacity += consdata->demands[endindices[endidx]];
8387 ++endidx;
8388 }
8389
8390 assert(freecapacity <= consdata->capacity);
8391 assert(endidx <= nvars);
8392
8393 /* --> endindex - points to the next job which will finish
8394 * j - points to the last job that has been released
8395 */
8396
8397 /* check freecapacity to be smaller than zero
8398 * then we will add cover constraints to the MIP
8399 */
8400 if( freecapacity < 0 && curtime >= hmin )
8401 {
8402 int nextprofilechange;
8403
8404 /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8405 if( j < nvars-1 )
8406 nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8407 else
8408 nextprofilechange = endvaluessorted[endidx];
8409
8410 nextprofilechange = MIN(nextprofilechange, hmax);
8411
8412 for( t = curtime; t < nextprofilechange; ++t )
8413 {
8414 SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8415
8416 /* create covering constraint */
8417 SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8418 }
8419 } /* end if freecapacity > 0 */
8420 } /*lint --e{850}*/
8421
8422 consdata->covercuts = TRUE;
8423
8424 /* free all buffer arrays */
8425 SCIPfreeBufferArray(scip, &endindices);
8426 SCIPfreeBufferArray(scip, &startindices);
8427 SCIPfreeBufferArray(scip, &endvaluessorted);
8428 SCIPfreeBufferArray(scip, &startvaluessorted);
8429 SCIPfreeBufferArray(scip, &endvalues);
8430 SCIPfreeBufferArray(scip, &startvalues);
8431
8432 return SCIP_OKAY;
8433}
8434
8435/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8436 * constraint
8437 */
8438static
8440 SCIP* scip, /**< SCIP data structure */
8441 SCIP_CONS* cons, /**< constraint to be checked */
8442 int* startindices, /**< permutation with rspect to the start times */
8443 int curtime, /**< current point in time */
8444 int nstarted, /**< number of jobs that start before the curtime or at curtime */
8445 int nfinished, /**< number of jobs that finished before curtime or at curtime */
8446 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8447 )
8448{
8449 SCIP_CONSDATA* consdata;
8450 SCIP_VAR** binvars;
8451 int* coefs;
8452 int nbinvars;
8453 char name[SCIP_MAXSTRLEN];
8454 int capacity;
8455 int b;
8456
8457 assert(nstarted > nfinished);
8458
8459 consdata = SCIPconsGetData(cons);
8460 assert(consdata != NULL);
8461 assert(consdata->nvars > 0);
8462
8463 capacity = consdata->capacity;
8464 assert(capacity > 0);
8465
8466 nbinvars = 0;
8467 SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8468
8469 /* construct row name */
8470 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8471
8472 if( cutsasconss )
8473 {
8474 SCIP_CONS* lincons;
8475
8476 /* create knapsack constraint for the given time point */
8477 SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8479
8480 for( b = 0; b < nbinvars; ++b )
8481 {
8482 SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8483 }
8484
8485 /* add and release the new constraint */
8486 SCIP_CALL( SCIPaddCons(scip, lincons) );
8487 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8488 }
8489 else
8490 {
8491 SCIP_ROW* row;
8492
8493 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8495
8496 for( b = 0; b < nbinvars; ++b )
8497 {
8498 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8499 }
8500
8503
8504 if( consdata->demandrowssize == 0 )
8505 {
8506 consdata->demandrowssize = 10;
8507 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8508 }
8509 if( consdata->ndemandrows == consdata->demandrowssize )
8510 {
8511 consdata->demandrowssize *= 2;
8512 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8513 }
8514
8515 consdata->demandrows[consdata->ndemandrows] = row;
8516 consdata->ndemandrows++;
8517 }
8518
8519 SCIPfreeBufferArrayNull(scip, &binvars);
8521
8522 return SCIP_OKAY;
8523}
8524
8525/** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8526 * row
8527 */
8528static
8530 SCIP* scip, /**< SCIP data structure */
8531 SCIP_CONS* cons, /**< constraint to be checked */
8532 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8533 )
8534{
8535 SCIP_CONSDATA* consdata;
8536
8537 int* starttimes; /* stores when each job is starting */
8538 int* endtimes; /* stores when each job ends */
8539 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8540 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8541
8542 int nvars; /* number of activities for this constraint */
8543 int freecapacity; /* remaining capacity */
8544 int curtime; /* point in time which we are just checking */
8545 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8546
8547 int hmin;
8548 int hmax;
8549
8550 int j;
8551
8552 assert(scip != NULL);
8553 assert(cons != NULL);
8554
8555 consdata = SCIPconsGetData(cons);
8556 assert(consdata != NULL);
8557
8558 nvars = consdata->nvars;
8559
8560 /* if no activities are associated with this cumulative then this constraint is redundant */
8561 if( nvars == 0 )
8562 return SCIP_OKAY;
8563
8564 assert(consdata->vars != NULL);
8565
8566 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8567 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8568 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8569 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8570
8571 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8572 SCIPconsGetName(cons), nvars);
8573
8574 /* create event point arrays */
8575 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8576 starttimes, endtimes, startindices, endindices, FALSE);
8577
8578 endindex = 0;
8579 freecapacity = consdata->capacity;
8580 hmin = consdata->hmin;
8581 hmax = consdata->hmax;
8582
8583 /* check each startpoint of a job whether the capacity is kept or not */
8584 for( j = 0; j < nvars; ++j )
8585 {
8586 curtime = starttimes[j];
8587 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8588
8589 if( curtime >= hmax )
8590 break;
8591
8592 /* remove the capacity requirments for all job which start at the curtime */
8593 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8594
8595 /* add the capacity requirments for all job which end at the curtime */
8596 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8597
8598 assert(freecapacity <= consdata->capacity);
8599 assert(endindex <= nvars);
8600
8601 /* endindex - points to the next job which will finish */
8602 /* j - points to the last job that has been released */
8603
8604 /* if free capacity is smaller than zero, then add rows to the LP */
8605 if( freecapacity < 0 && curtime >= hmin )
8606 {
8607 int nextstarttime;
8608 int t;
8609
8610 /* step forward until next job is released and see whether capacity constraint is met or not */
8611 if( j < nvars-1 )
8612 nextstarttime = starttimes[j+1];
8613 else
8614 nextstarttime = endtimes[nvars-1];
8615
8616 nextstarttime = MIN(nextstarttime, hmax);
8617
8618 /* create capacity restriction row for current event point */
8619 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8620
8621 /* create for all points in time between the current event point and next start event point a row if the free
8622 * capacity is still smaller than zero */
8623 for( t = curtime+1 ; t < nextstarttime; ++t )
8624 {
8625 /* add the capacity requirments for all job which end at the curtime */
8626 addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8627
8628 if( freecapacity < 0 )
8629 {
8630 /* add constraint */
8631 SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8632
8633 /* create capacity restriction row */
8634 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8635 }
8636 else
8637 break;
8638 }
8639 }
8640 } /*lint --e{850}*/
8641
8642 /* free all buffer arrays */
8643 SCIPfreeBufferArray(scip, &endindices);
8644 SCIPfreeBufferArray(scip, &startindices);
8645 SCIPfreeBufferArray(scip, &endtimes);
8646 SCIPfreeBufferArray(scip, &starttimes);
8647
8648 return SCIP_OKAY;
8649}
8650
8651/** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8652 * capacity is larger than the capacity of the cumulative constraint
8653 * - for each necessary point in time:
8654 *
8655 * sum_j sum_t demand_j * x_{j,t} <= capacity
8656 *
8657 * where x(j,t) is the binary variables of job j at time t
8658 */
8659static
8661 SCIP* scip, /**< SCIP data structure */
8662 SCIP_CONS* cons, /**< cumulative constraint */
8663 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8664 )
8665{
8666 SCIP_CONSDATA* consdata;
8667
8668 consdata = SCIPconsGetData(cons);
8669 assert(consdata != NULL);
8670 assert(consdata->demandrows == NULL);
8671 assert(consdata->ndemandrows == 0);
8672
8673 /* collect the linking constraints */
8674 if( consdata->linkingconss == NULL )
8675 {
8677 }
8678
8679 SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8680
8681 /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8682 if( cutsasconss )
8683 {
8684 if( SCIPconsIsInitial(cons) )
8685 {
8687 }
8688 if( SCIPconsIsSeparated(cons) )
8689 {
8691 }
8692 if( SCIPconsIsEnforced(cons) )
8693 {
8695 }
8696 }
8697
8698 return SCIP_OKAY;
8699}
8700
8701/** adds linear relaxation of cumulative constraint to the LP */
8702static
8704 SCIP* scip, /**< SCIP data structure */
8705 SCIP_CONS* cons, /**< cumulative constraint */
8706 SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8707 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8708 )
8709{
8710 SCIP_CONSDATA* consdata;
8711 int r;
8712
8713 consdata = SCIPconsGetData(cons);
8714 assert(consdata != NULL);
8715
8716 if( consdata->demandrows == NULL )
8717 {
8718 assert(consdata->ndemandrows == 0);
8719
8720 SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8721
8722 return SCIP_OKAY;
8723 }
8724
8725 for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8726 {
8727 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8728 {
8729 assert(consdata->demandrows[r] != NULL);
8730 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8731 }
8732 }
8733
8734 return SCIP_OKAY;
8735}
8736
8737/** checks constraint for violation, and adds it as a cut if possible */
8738static
8740 SCIP* scip, /**< SCIP data structure */
8741 SCIP_CONS* cons, /**< cumulative constraint to be separated */
8742 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8743 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8744 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8745 )
8746{ /*lint --e{715}*/
8747 SCIP_CONSDATA* consdata;
8748 int ncuts;
8749 int r;
8750
8751 assert(scip != NULL);
8752 assert(cons != NULL);
8753 assert(separated != NULL);
8754 assert(cutoff != NULL);
8755
8756 *separated = FALSE;
8757 *cutoff = FALSE;
8758
8759 consdata = SCIPconsGetData(cons);
8760 assert(consdata != NULL);
8761
8762 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8763
8764 if( consdata->demandrows == NULL )
8765 {
8766 assert(consdata->ndemandrows == 0);
8767
8769
8770 return SCIP_OKAY;
8771 }
8772
8773 ncuts = 0;
8774
8775 /* check each row that is not contained in LP */
8776 for( r = 0; r < consdata->ndemandrows; ++r )
8777 {
8778 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8779 {
8780 SCIP_Real feasibility;
8781
8782 if( sol != NULL )
8783 feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8784 else
8785 feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8786
8787 if( SCIPisFeasNegative(scip, feasibility) )
8788 {
8789 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8790 if ( *cutoff )
8791 {
8793 return SCIP_OKAY;
8794 }
8795 *separated = TRUE;
8796 ncuts++;
8797 }
8798 }
8799 }
8800
8801 if( ncuts > 0 )
8802 {
8803 SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8804
8805 /* if successful, reset age of constraint */
8807 (*separated) = TRUE;
8808 }
8809
8810 return SCIP_OKAY;
8811}
8812
8813/** checks constraint for violation, and adds it as a cut if possible */
8814static
8816 SCIP* scip, /**< SCIP data structure */
8817 SCIP_CONS* cons, /**< logic or constraint to be separated */
8818 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8819 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8820 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8821 )
8822{
8823 SCIP_CONSDATA* consdata;
8824 SCIP_ROW* row;
8825 SCIP_Real minfeasibility;
8826 int r;
8827
8828 assert(scip != NULL);
8829 assert(cons != NULL);
8830 assert(separated != NULL);
8831 assert(cutoff != NULL);
8832
8833 *separated = FALSE;
8834 *cutoff = FALSE;
8835
8836 consdata = SCIPconsGetData(cons);
8837 assert(consdata != NULL);
8838
8839 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8840
8841 /* collect the linking constraints */
8842 if( consdata->linkingconss == NULL )
8843 {
8845 }
8846
8847 if( !consdata->covercuts )
8848 {
8849 SCIP_CALL( createCoverCuts(scip, cons) );
8850 }
8851
8852 row = NULL;
8853 minfeasibility = SCIPinfinity(scip);
8854
8855 /* check each row of small covers that is not contained in LP */
8856 for( r = 0; r < consdata->nscoverrows; ++r )
8857 {
8858 if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8859 {
8860 SCIP_Real feasibility;
8861
8862 assert(consdata->scoverrows[r] != NULL);
8863 if( sol != NULL )
8864 feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8865 else
8866 feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8867
8868 if( minfeasibility > feasibility )
8869 {
8870 minfeasibility = feasibility;
8871 row = consdata->scoverrows[r];
8872 }
8873 }
8874 }
8875
8876 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8877
8878 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8879 {
8880 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8881 SCIPconsGetName(cons), minfeasibility);
8882
8883 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8885 if ( *cutoff )
8886 return SCIP_OKAY;
8887 (*separated) = TRUE;
8888 }
8889
8890 minfeasibility = SCIPinfinity(scip);
8891 row = NULL;
8892
8893 /* check each row of small covers that is not contained in LP */
8894 for( r = 0; r < consdata->nbcoverrows; ++r )
8895 {
8896 if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8897 {
8898 SCIP_Real feasibility;
8899
8900 assert(consdata->bcoverrows[r] != NULL);
8901 if( sol != NULL )
8902 feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8903 else
8904 feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8905
8906 if( minfeasibility > feasibility )
8907 {
8908 minfeasibility = feasibility;
8909 row = consdata->bcoverrows[r];
8910 }
8911 }
8912 }
8913
8914 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8915
8916 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8917 {
8918 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8919 SCIPconsGetName(cons), minfeasibility);
8920
8921 assert(row != NULL);
8922 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8924 if ( *cutoff )
8925 return SCIP_OKAY;
8926 (*separated) = TRUE;
8927 }
8928
8929 return SCIP_OKAY;
8930}
8931
8932/** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8933static
8935 SCIP* scip, /**< SCIP data structure */
8936 SCIP_CONS* cons, /**< constraint to be checked */
8937 int* startindices, /**< permutation with rspect to the start times */
8938 int curtime, /**< current point in time */
8939 int nstarted, /**< number of jobs that start before the curtime or at curtime */
8940 int nfinished, /**< number of jobs that finished before curtime or at curtime */
8941 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
8942 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
8943 )
8944{
8945 SCIP_CONSDATA* consdata;
8946 char name[SCIP_MAXSTRLEN];
8947 int lhs; /* left hand side of constraint */
8948
8949 SCIP_VAR** activevars;
8950 SCIP_ROW* row;
8951
8952 int v;
8953
8954 assert(nstarted > nfinished);
8955
8956 consdata = SCIPconsGetData(cons);
8957 assert(consdata != NULL);
8958 assert(consdata->nvars > 0);
8959
8960 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8961
8962 SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8963
8964 if( lower )
8965 {
8966 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8967
8968 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
8969 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8970 }
8971 else
8972 {
8973 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8974 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8975 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8976 }
8977
8979
8980 for( v = 0; v < nstarted - nfinished; ++v )
8981 {
8982 SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
8983 }
8984
8987
8988 SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
8989
8990 SCIP_CALL( SCIPreleaseRow(scip, &row) );
8991
8992 /* free buffers */
8993 SCIPfreeBufferArrayNull(scip, &activevars);
8994
8995 return SCIP_OKAY;
8996}
8997
8998/** checks constraint for violation, and adds it as a cut if possible */
8999static
9001 SCIP* scip, /**< SCIP data structure */
9002 SCIP_CONS* cons, /**< cumulative constraint to be separated */
9003 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9004 SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9005 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9006 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9007 )
9008{
9009 SCIP_CONSDATA* consdata;
9010
9011 int* starttimes; /* stores when each job is starting */
9012 int* endtimes; /* stores when each job ends */
9013 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9014 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9015
9016 int nvars; /* number of activities for this constraint */
9017 int freecapacity; /* remaining capacity */
9018 int curtime; /* point in time which we are just checking */
9019 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9020
9021 int hmin;
9022 int hmax;
9023 int j;
9024
9025 assert(scip != NULL);
9026 assert(cons != NULL);
9027
9028 consdata = SCIPconsGetData(cons);
9029 assert(consdata != NULL);
9030
9031 nvars = consdata->nvars;
9032
9033 /* if no activities are associated with this cumulative then this constraint is redundant */
9034 if( nvars <= 1 )
9035 return SCIP_OKAY;
9036
9037 assert(consdata->vars != NULL);
9038
9039 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9040 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9041 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9042 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9043
9044 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9045 SCIPconsGetName(cons), nvars);
9046
9047 /* create event point arrays */
9048 createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9049
9050 /* now nvars might be smaller than before! */
9051
9052 endindex = 0;
9053 freecapacity = consdata->capacity;
9054 hmin = consdata->hmin;
9055 hmax = consdata->hmax;
9056
9057 /* check each startpoint of a job whether the capacity is kept or not */
9058 for( j = 0; j < nvars && !(*cutoff); ++j )
9059 {
9060 curtime = starttimes[j];
9061
9062 if( curtime >= hmax )
9063 break;
9064
9065 /* remove the capacity requirements for all job which start at the curtime */
9066 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9067
9068 /* add the capacity requirments for all job which end at the curtime */
9069 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9070
9071 assert(freecapacity <= consdata->capacity);
9072 assert(endindex <= nvars);
9073
9074 /* endindex - points to the next job which will finish */
9075 /* j - points to the last job that has been released */
9076
9077 /* if free capacity is smaller than zero, then add rows to the LP */
9078 if( freecapacity < 0 && curtime >= hmin)
9079 {
9080 /* create capacity restriction row for current event point */
9081 SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9082 *separated = TRUE;
9083 }
9084 } /*lint --e{850}*/
9085
9086 /* free all buffer arrays */
9087 SCIPfreeBufferArray(scip, &endindices);
9088 SCIPfreeBufferArray(scip, &startindices);
9089 SCIPfreeBufferArray(scip, &endtimes);
9090 SCIPfreeBufferArray(scip, &starttimes);
9091
9092 return SCIP_OKAY;
9093}
9094
9095/**@} */
9096
9097
9098/**@name Presolving
9099 *
9100 * @{
9101 */
9102
9103#ifndef NDEBUG
9104/** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9105 * correct
9106 */
9107static
9109 SCIP* scip, /**< SCIP data structure */
9110 SCIP_CONS* cons /**< constraint to be checked */
9111 )
9112{
9113 SCIP_CONSDATA* consdata;
9114 int capacity;
9115 int nvars;
9116 int j;
9117
9118 assert(scip != NULL);
9119 assert(cons != NULL);
9120
9121 consdata = SCIPconsGetData(cons);
9122 assert(consdata != NULL);
9123
9124 nvars = consdata->nvars;
9125
9126 /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9127 if( nvars <= 1 )
9128 return TRUE;
9129
9130 assert(consdata->vars != NULL);
9131 capacity = consdata->capacity;
9132
9133 /* check each activity: if demand is larger than capacity the problem is infeasible */
9134 for ( j = 0; j < nvars; ++j )
9135 {
9136 if( consdata->demands[j] > capacity )
9137 return FALSE;
9138 }
9139
9140 return TRUE;
9141}
9142#endif
9143
9144/** delete constraint if it consists of at most one job
9145 *
9146 * @todo this method needs to be adjusted w.r.t. effective horizon
9147 */
9148static
9150 SCIP* scip, /**< SCIP data structure */
9151 SCIP_CONS* cons, /**< constraint to propagate */
9152 int* ndelconss, /**< pointer to store the number of deleted constraints */
9153 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9154 )
9155{
9156 SCIP_CONSDATA* consdata;
9157
9158 assert(scip != NULL);
9159 assert(cons != NULL);
9160
9161 consdata = SCIPconsGetData(cons);
9162 assert(consdata != NULL);
9163
9164 if( consdata->nvars == 0 )
9165 {
9166 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9167
9168 SCIP_CALL( SCIPdelCons(scip, cons) );
9169 (*ndelconss)++;
9170 }
9171 else if( consdata->nvars == 1 )
9172 {
9173 if( consdata->demands[0] > consdata->capacity )
9174 (*cutoff) = TRUE;
9175 else
9176 {
9177 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9178
9179 SCIP_CALL( SCIPdelCons(scip, cons) );
9180 (*ndelconss)++;
9181 }
9182 }
9183
9184 return SCIP_OKAY;
9185}
9186
9187/** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9188 * this is done in the SCIP_DECL_CONSINITPRE() callback
9189 */
9190static
9192 SCIP* scip, /**< SCIP data structure */
9193 SCIP_CONS* cons /**< constraint to propagate */
9194 )
9195{
9196 SCIP_CONSDATA* consdata;
9197 SCIP_VAR* var;
9198 int demand;
9199 int duration;
9200 int hmin;
9201 int hmax;
9202 int est;
9203 int lct;
9204 int j;
9205
9206 assert(scip != NULL);
9207 assert(cons != NULL);
9208
9209 consdata = SCIPconsGetData(cons);
9210 assert(consdata != NULL);
9211
9212 hmin = consdata->hmin;
9213 hmax = consdata->hmax;
9214
9215 SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9216 SCIPconsGetName(cons), hmin, hmax);
9217
9218 for( j = consdata->nvars-1; j >= 0; --j )
9219 {
9220 var = consdata->vars[j];
9221 demand = consdata->demands[j];
9222 duration = consdata->durations[j];
9223
9224 /* earliest completion time (ect) and latest start time (lst) */
9226 lct = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9227
9228 if( demand == 0 || duration == 0 )
9229 {
9230 /* jobs with zero demand or zero duration can be removed */
9231 SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9232 SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9233
9234 /* remove variable form constraint */
9235 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9236 }
9237 else if( est >= hmax || lct <= hmin )
9238 {
9239 SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9240 SCIPvarGetName(var), est, lct - duration, duration);
9241
9242 /* delete variable at the given position */
9243 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9244
9245 /* for the statistic we count the number of jobs which are irrelevant */
9247 }
9248 }
9249
9250 return SCIP_OKAY;
9251}
9252
9253/** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9254static
9256 SCIP* scip, /**< SCIP data structure */
9257 SCIP_CONSDATA* consdata, /**< constraint data */
9258 int pos, /**< position of job in the consdata */
9259 int* nchgbds, /**< pointer to store the number of changed bounds */
9260 int* naddconss, /**< pointer to store the number of added constraints */
9261 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9262 )
9263{
9264 SCIP_VAR* var;
9265 SCIP_Bool tightened;
9266 int duration;
9267 int ect;
9268 int lst;
9269
9270 assert(scip != NULL);
9271
9272 /* zero energy jobs should be removed already */
9273 assert(consdata->durations[pos] > 0);
9274 assert(consdata->demands[pos] > 0);
9275
9276 var = consdata->vars[pos];
9277 assert(var != NULL);
9278 duration = consdata->durations[pos];
9279
9280 /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9281 SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9282 SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9283
9284 /* earliest completion time (ect) and latest start time (lst) */
9285 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9287
9288 /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9289 if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9290 return SCIP_OKAY;
9291
9292 if( ect > consdata->hmin && lst < consdata->hmax )
9293 {
9294 /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9295 *cutoff = TRUE;
9296 }
9297 else if( lst < consdata->hmax )
9298 {
9299 /* move the latest start time of this job in such a way that it finishes before or at hmin */
9300 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9301 assert(tightened);
9302 assert(!(*cutoff));
9303 (*nchgbds)++;
9304 }
9305 else if( ect > consdata->hmin )
9306 {
9307 /* move the earliest start time of this job in such a way that it starts after or at hmax */
9308 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9309 assert(tightened);
9310 assert(!(*cutoff));
9311 (*nchgbds)++;
9312 }
9313 else
9314 {
9315 /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9316 * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9317 *
9318 * (var <= hmin - duration) /\ (var >= hmax)
9319 */
9320 SCIP_CONS* cons;
9321
9322 SCIP_VAR* vartuple[2];
9323 SCIP_BOUNDTYPE boundtypetuple[2];
9324 SCIP_Real boundtuple[2];
9325
9326 char name[SCIP_MAXSTRLEN];
9327 int leftbound;
9328 int rightbound;
9329
9330 leftbound = consdata->hmin - duration;
9331 rightbound = consdata->hmax;
9332
9333 /* allocate temporary memory for arrays */
9334 vartuple[0] = var;
9335 vartuple[1] = var;
9336 boundtuple[0] = (SCIP_Real)leftbound;
9337 boundtuple[1] = (SCIP_Real)rightbound;
9338 boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9339 boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9340
9341 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9342 SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9343
9344 /* create and add bounddisjunction constraint */
9345 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9346 TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9347
9349
9350 /* add and release the new constraint */
9351 SCIP_CALL( SCIPaddCons(scip, cons) );
9352 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9353 (*naddconss)++;
9354 }
9355
9356 return SCIP_OKAY;
9357}
9358
9359/** try to removed over sizeed jobs (the demand is larger than the capacity) */
9360static
9362 SCIP* scip, /**< SCIP data structure */
9363 SCIP_CONS* cons, /**< constraint */
9364 int* nchgbds, /**< pointer to store the number of changed bounds */
9365 int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9366 int* naddconss, /**< pointer to store the number of added constraints */
9367 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9368 )
9369{
9370 SCIP_CONSDATA* consdata;
9371 int capacity;
9372 int j;
9373
9374 consdata = SCIPconsGetData(cons);
9375 assert(consdata != NULL);
9376
9377 /* if a cutoff was already detected just return */
9378 if( *cutoff )
9379 return SCIP_OKAY;
9380
9381 capacity = consdata->capacity;
9382
9383 for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9384 {
9385 if( consdata->demands[j] > capacity )
9386 {
9387 SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9388
9389 /* remove variable form constraint */
9390 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9391 (*nchgcoefs)++;
9392 }
9393 }
9394
9395 SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9396
9397 return SCIP_OKAY;
9398}
9399
9400/** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9401static
9403 SCIP* scip, /**< SCIP data structure */
9404 SCIP_VAR* var, /**< integer variable to fix */
9405 SCIP_Bool uplock, /**< has thet start time variable a up lock */
9406 int* nfixedvars /**< pointer to store the number fixed variables */
9407 )
9408{
9409 SCIP_Bool infeasible;
9410 SCIP_Bool tightened;
9411 SCIP_Bool roundable;
9412
9413 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9414 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9415 */
9417 return SCIP_OKAY;
9418
9419 /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9420 * handler is the only one locking that variable up
9421 */
9422 assert(uplock == TRUE || uplock == FALSE);
9423 assert((int)TRUE == 1); /*lint !e506*/
9424 assert((int)FALSE == 0); /*lint !e506*/
9425
9426 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9427 return SCIP_OKAY;
9428
9429 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9430
9431 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9432 * (the transformed problem is always a minimization problem)
9433 */
9434 if( !roundable )
9435 return SCIP_OKAY;
9436
9437 SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9439
9440 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9441 assert(!infeasible);
9442
9443 if( tightened )
9444 {
9445 SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9446 (*nfixedvars)++;
9447 }
9448
9449 return SCIP_OKAY;
9450}
9451
9452/** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9453static
9455 SCIP* scip, /**< SCIP data structure */
9456 SCIP_VAR* var, /**< integer variable to fix */
9457 SCIP_Bool downlock, /**< has the variable a down lock */
9458 int* nfixedvars /**< pointer to store the number fixed variables */
9459 )
9460{
9461 SCIP_Bool infeasible;
9462 SCIP_Bool tightened;
9463 SCIP_Bool roundable;
9464
9465 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9466 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9467 */
9469 return SCIP_OKAY;
9470
9471 /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9472 * handler is the only one locking that variable down
9473 */
9474 assert(downlock == TRUE || downlock == FALSE);
9475 assert((int)TRUE == 1); /*lint !e506*/
9476 assert((int)FALSE == 0); /*lint !e506*/
9477
9478 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9479 return SCIP_OKAY;
9480
9481 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9482
9483 /* is it possible, to round variable down w.r.t. objective function? */
9484 if( !roundable )
9485 return SCIP_OKAY;
9486
9487 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9488 assert(!infeasible);
9489
9490 if( tightened )
9491 {
9492 SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9493 (*nfixedvars)++;
9494 }
9495
9496 return SCIP_OKAY;
9497}
9498
9499/** normalize cumulative condition */
9500static
9502 SCIP* scip, /**< SCIP data structure */
9503 int nvars, /**< number of start time variables (activities) */
9504 int* demands, /**< array of demands */
9505 int* capacity, /**< pointer to store the changed cumulative capacity */
9506 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9507 int* nchgsides /**< pointer to count number of side changes */
9508 )
9509{ /*lint --e{715}*/
9510 SCIP_Longint gcd;
9511 int mindemand1;
9512 int mindemand2;
9513 int v;
9514
9515 if( *capacity == 1 || nvars <= 1 )
9516 return;
9517
9518 assert(demands[nvars-1] <= *capacity);
9519 assert(demands[nvars-2] <= *capacity);
9520
9521 gcd = (SCIP_Longint)demands[nvars-1];
9522 mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9523 mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9524
9525 for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9526 {
9527 assert(mindemand1 <= mindemand2);
9528 assert(demands[v] <= *capacity);
9529
9530 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9531
9532 if( mindemand1 > demands[v] )
9533 {
9534 mindemand2 = mindemand1;
9535 mindemand1 = demands[v];
9536 }
9537 else if( mindemand2 > demands[v] )
9538 mindemand2 = demands[v];
9539 }
9540
9541 if( mindemand1 + mindemand2 > *capacity )
9542 {
9543 SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9544
9545 for( v = 0; v < nvars; ++v )
9546 demands[v] = 1;
9547
9548 (*capacity) = 1;
9549
9550 (*nchgcoefs) += nvars;
9551 (*nchgsides)++;
9552 }
9553 else if( gcd >= 2 )
9554 {
9555 SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9556
9557 for( v = 0; v < nvars; ++v )
9558 demands[v] /= (int) gcd;
9559
9560 (*capacity) /= (int) gcd;
9561
9562 (*nchgcoefs) += nvars;
9563 (*nchgsides)++;
9564 }
9565}
9566
9567/** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9568 * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9569 * capacity since in that case none of the jobs can run in parallel
9570 */
9571static
9573 SCIP* scip, /**< SCIP data structure */
9574 SCIP_CONS* cons, /**< cumulative constraint */
9575 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9576 int* nchgsides /**< pointer to count number of side changes */
9577 )
9578{
9579 SCIP_CONSDATA* consdata;
9580 int capacity;
9581
9582 assert(nchgcoefs != NULL);
9583 assert(nchgsides != NULL);
9584 assert(!SCIPconsIsModifiable(cons));
9585
9586 consdata = SCIPconsGetData(cons);
9587 assert(consdata != NULL);
9588
9589 if( consdata->normalized )
9590 return;
9591
9592 capacity = consdata->capacity;
9593
9594 /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9595
9596 normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9597
9598 consdata->normalized = TRUE;
9599
9600 if( capacity > consdata->capacity )
9601 consdata->varbounds = FALSE;
9602}
9603
9604/** computes for the given cumulative condition the effective horizon */
9605static
9607 SCIP* scip, /**< SCIP data structure */
9608 int nvars, /**< number of variables (jobs) */
9609 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9610 int* durations, /**< array containing corresponding durations */
9611 int* demands, /**< array containing corresponding demands */
9612 int capacity, /**< available cumulative capacity */
9613 int* hmin, /**< pointer to store the left bound of the effective horizon */
9614 int* hmax, /**< pointer to store the right bound of the effective horizon */
9615 int* split /**< point were the cumulative condition can be split */
9616 )
9617{
9618 SCIP_PROFILE* profile;
9619
9620 /* create empty resource profile with infinity resource capacity */
9621 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9622
9623 /* create worst case resource profile */
9624 SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9625
9626 /* print resource profile in if SCIP_DEBUG is defined */
9628
9629 /* computes the first time point where the resource capacity can be violated */
9630 (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9631
9632 /* computes the first time point where the resource capacity is satisfied for sure */
9633 (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9634
9635 (*split) = (*hmax);
9636
9637 if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9638 {
9639 int* timepoints;
9640 int* loads;
9641 int ntimepoints;
9642 int t;
9643
9644 /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9645 * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9646 * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9647 * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9648 * explain the certain "old" bound changes
9649 */
9650
9651 /* search for time points */
9652 ntimepoints = SCIPprofileGetNTimepoints(profile);
9653 timepoints = SCIPprofileGetTimepoints(profile);
9654 loads = SCIPprofileGetLoads(profile);
9655
9656 /* 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 */
9657 for( t = 0; t < ntimepoints; ++t )
9658 {
9659 /* ignore all time points before the effective horizon */
9660 if( timepoints[t] <= *hmin )
9661 continue;
9662
9663 /* ignore all time points after the effective horizon */
9664 if( timepoints[t] >= *hmax )
9665 break;
9666
9667 /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9668 * can split the cumulative constraint into two cumulative constraints
9669 */
9670 if( loads[t] <= capacity )
9671 {
9672 (*split) = timepoints[t];
9673 break;
9674 }
9675 }
9676 }
9677
9678 /* free worst case profile */
9679 SCIPprofileFree(&profile);
9680
9681 return SCIP_OKAY;
9682}
9683
9684/** creates and adds a cumulative constraint */
9685static
9687 SCIP* scip, /**< SCIP data structure */
9688 const char* name, /**< name of constraint */
9689 int nvars, /**< number of variables (jobs) */
9690 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9691 int* durations, /**< array containing corresponding durations */
9692 int* demands, /**< array containing corresponding demands */
9693 int capacity, /**< available cumulative capacity */
9694 int hmin, /**< left bound of time axis to be considered (including hmin) */
9695 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9696 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9697 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9698 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9699 * Usually set to TRUE. */
9700 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9701 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9702 SCIP_Bool check, /**< should the constraint be checked for feasibility?
9703 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9704 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9705 * Usually set to TRUE. */
9706 SCIP_Bool local, /**< is constraint only valid locally?
9707 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9708 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9709 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9710 * adds coefficients to this constraint. */
9711 SCIP_Bool dynamic, /**< is constraint subject to aging?
9712 * Usually set to FALSE. Set to TRUE for own cuts which
9713 * are seperated as constraints. */
9714 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9715 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9716 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9717 * if it may be moved to a more global node?
9718 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9719 )
9720{
9721 SCIP_CONS* cons;
9722
9723 /* creates cumulative constraint and adds it to problem */
9724 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9725 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9726
9727 /* adjust the effective time horizon of the new constraint */
9728 SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9729 SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9730
9731 /* add and release new cumulative constraint */
9732 SCIP_CALL( SCIPaddCons(scip, cons) );
9733 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9734
9735 return SCIP_OKAY;
9736}
9737
9738/** computes the effective horizon and checks if the constraint can be decompsed */
9739static
9741 SCIP* scip, /**< SCIP data structure */
9742 SCIP_CONS* cons, /**< cumulative constraint */
9743 int* ndelconss, /**< pointer to store the number of deleted constraints */
9744 int* naddconss, /**< pointer to store the number of added constraints */
9745 int* nchgsides /**< pointer to store the number of changed sides */
9746 )
9747{
9748 SCIP_CONSDATA* consdata;
9749 int hmin;
9750 int hmax;
9751 int split;
9752
9753 consdata = SCIPconsGetData(cons);
9754 assert(consdata != NULL);
9755
9756 if( consdata->nvars <= 1 )
9757 return SCIP_OKAY;
9758
9759 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9760 consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9761
9762 /* check if this time point improves the effective horizon */
9763 if( consdata->hmin < hmin )
9764 {
9765 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9766
9767 consdata->hmin = hmin;
9768 (*nchgsides)++;
9769 }
9770
9771 /* check if this time point improves the effective horizon */
9772 if( consdata->hmax > hmax )
9773 {
9774 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9775 consdata->hmax = hmax;
9776 (*nchgsides)++;
9777 }
9778
9779 /* check if the constraint is redundant */
9780 if( consdata->hmax <= consdata->hmin )
9781 {
9782 SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9783 SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9784
9785 SCIP_CALL( SCIPdelCons(scip, cons) );
9786 (*ndelconss)++;
9787 }
9788 else if( consdata->hmin < split && split < consdata->hmax )
9789 {
9790 char name[SCIP_MAXSTRLEN];
9791 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9792
9793 SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9794 SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9795
9796 assert(split < consdata->hmax);
9797
9798 /* creates cumulative constraint and adds it to problem */
9799 SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9800 consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9803
9804 /* adjust the effective time horizon of the constraint */
9805 consdata->hmax = split;
9806
9807 assert(consdata->hmin < consdata->hmax);
9808
9809 /* for the statistic we count the number of time we decompose a cumulative constraint */
9811 (*naddconss)++;
9812 }
9813
9814 return SCIP_OKAY;
9815}
9816
9817
9818/** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9819 *
9820 * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9821 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9822 *
9823 * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9824 * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9825 * down-lock of the corresponding start time variable can be removed.
9826 *
9827 * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9828 * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9829 * negative, than the job can be dual fixed to its earlier start time (est).
9830 *
9831 * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9832 * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9833 * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9834 *
9835 * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9836 * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9837 * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9838 * form variable domain is dual feasible.
9839 *
9840 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9841 * the cumulative condition; The deletion has to be done later.
9842 */
9843static
9845 SCIP* scip, /**< SCIP data structure */
9846 int nvars, /**< number of start time variables (activities) */
9847 SCIP_VAR** vars, /**< array of start time variables */
9848 int* durations, /**< array of durations */
9849 int hmin, /**< left bound of time axis to be considered (including hmin) */
9850 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9851 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9852 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9853 SCIP_CONS* cons, /**< underlying constraint, or NULL */
9854 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9855 int* nfixedvars, /**< pointer to store the number of fixed variables */
9856 int* nchgsides, /**< pointer to store the number of changed sides */
9857 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9858 )
9859{
9860 SCIP_Real* downimpllbs;
9861 SCIP_Real* downimplubs;
9862 SCIP_Real* downproplbs;
9863 SCIP_Real* downpropubs;
9864 SCIP_Real* upimpllbs;
9865 SCIP_Real* upimplubs;
9866 SCIP_Real* upproplbs;
9867 SCIP_Real* uppropubs;
9868
9869 int firstminect;
9870 int secondminect;
9871 int v;
9872
9873 /* get temporary memory for storing probing results needed for step (4) and (5) */
9874 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9875 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9876 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9877 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9878 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9879 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9880 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9881 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9882
9883 assert(scip != NULL);
9884 assert(nvars > 1);
9885 assert(cons != NULL);
9886
9887 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9888
9889 firstminect = INT_MAX;
9890 secondminect = INT_MAX;
9891
9892 /* compute the two smallest earlier completion times; which are needed for step (5) */
9893 for( v = 0; v < nvars; ++v )
9894 {
9895 int ect;
9896
9897 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9898
9899 if( ect < firstminect )
9900 {
9901 secondminect = firstminect;
9902 firstminect = ect;
9903 }
9904 else if( ect < secondminect )
9905 secondminect = ect;
9906 }
9907
9908 /* loop over all jobs and check if one of the 5 reductions can be applied */
9909 for( v = 0; v < nvars; ++v )
9910 {
9911 SCIP_VAR* var;
9912 int duration;
9913
9914 int alternativelb;
9915 int minect;
9916 int est;
9917 int ect;
9918 int lst;
9919 int lct;
9920
9921 var = vars[v];
9922 assert(var != NULL);
9923
9924 duration = durations[v];
9925 assert(duration > 0);
9926
9927 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9928 * time (lct)
9929 */
9931 ect = est + duration;
9933 lct = lst + duration;
9934
9935 /* compute the earliest completion time of all remaining jobs */
9936 if( ect == firstminect )
9937 minect = secondminect;
9938 else
9939 minect = firstminect;
9940
9941 /* compute potential alternative lower bound (step (4) and (5)) */
9942 alternativelb = MAX(hmin+1, minect);
9943 alternativelb = MIN(alternativelb, hmax);
9944
9945 if( lct <= hmin )
9946 {
9947 /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9948 * cumulative condition
9949 */
9950 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9951 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9952
9953 /* mark variable to be irrelevant */
9954 irrelevants[v] = TRUE;
9955
9956 /* for the statistic we count the number of jobs which are irrelevant */
9958 }
9959 else if( lst <= hmin && SCIPconsIsChecked(cons) )
9960 {
9961 /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9962 * so the down lock can be omitted
9963 */
9964
9965 assert(downlocks != NULL);
9966 assert(uplocks != NULL);
9967
9968 if( !uplocks[v] )
9969 {
9970 /* the variables has no up lock and we can also remove the down lock;
9971 * => lst <= hmin and ect >= hmax
9972 * => remove job and reduce capacity by the demand of that job
9973 *
9974 * We mark the job to be deletable. The removement together with the capacity reducion is done later
9975 */
9976
9977 SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
9978 SCIPvarGetName(var), ect - duration, lst, duration);
9979
9980 /* mark variable to be irrelevant */
9981 irrelevants[v] = TRUE;
9982
9983 /* for the statistic we count the number of jobs which always run during the effective horizon */
9985 }
9986
9987 if( downlocks[v] )
9988 {
9989 SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
9990 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9991
9992 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
9993 downlocks[v] = FALSE;
9994 (*nchgsides)++;
9995
9996 /* for the statistic we count the number of removed locks */
9998 }
9999 }
10000 else if( ect <= hmin )
10001 {
10002 /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10003 * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10004 * removed form the cumulative condition after it was fixed to its earliest start time
10005 */
10006
10007 /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10008 * bound;
10009 */
10010 if( downlocks != NULL && SCIPconsIsChecked(cons) )
10011 {
10012 /* fix integer start time variable if possible to it lower bound */
10013 SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10014 }
10015
10016 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10017 {
10018 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10019 SCIPvarGetName(var), ect - duration, lst, duration);
10020
10021 /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10022 assert(boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10023
10024 /* mark variable to be irrelevant */
10025 irrelevants[v] = TRUE;
10026
10027 /* for the statistic we count the number of jobs which are dual fixed */
10029 }
10030 }
10031 else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10032 {
10033 assert(downlocks != NULL);
10034
10035 /* check step (4) and (5) */
10036
10037 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10038 * is in favor of rounding the variable down
10039 */
10040 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10041 {
10042 SCIP_Bool roundable;
10043
10044 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10045
10046 if( roundable )
10047 {
10048 if( alternativelb > lst )
10049 {
10050 SCIP_Bool infeasible;
10051 SCIP_Bool fixed;
10052
10053 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10054 assert(!infeasible);
10055 assert(fixed);
10056
10057 (*nfixedvars)++;
10058
10059 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10060 * constraints
10061 */
10063 }
10064 else
10065 {
10066 SCIP_Bool success;
10067
10068 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10069 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10070 * infeasible we can apply the dual reduction; otherwise we do nothing
10071 */
10072 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10073 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10074 nfixedvars, &success, cutoff) );
10075
10076 if( success )
10077 {
10079 }
10080 }
10081 }
10082 }
10083 }
10084
10085 SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10086 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10087 }
10088
10089 /* free temporary memory */
10090 SCIPfreeBufferArray(scip, &uppropubs);
10091 SCIPfreeBufferArray(scip, &upproplbs);
10092 SCIPfreeBufferArray(scip, &upimplubs);
10093 SCIPfreeBufferArray(scip, &upimpllbs);
10094 SCIPfreeBufferArray(scip, &downpropubs);
10095 SCIPfreeBufferArray(scip, &downproplbs);
10096 SCIPfreeBufferArray(scip, &downimplubs);
10097 SCIPfreeBufferArray(scip, &downimpllbs);
10098
10099 return SCIP_OKAY;
10100}
10101
10102/** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10103 *
10104 * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10105 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10106 *
10107 * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10108 * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10109 * up-lock of the corresponding start time variable can be removed.
10110 *
10111 * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10112 * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10113 * positive, than the job can be dual fixed to its latest start time (lst).
10114 *
10115 * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10116 * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10117 * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10118 * of the corresponding job).
10119
10120 * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10121 * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10122 * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10123 * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10124 *
10125 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10126 * the cumulative condition; The deletion has to be done later.
10127 */
10128static
10130 SCIP* scip, /**< SCIP data structure */
10131 int nvars, /**< number of start time variables (activities) */
10132 SCIP_VAR** vars, /**< array of start time variables */
10133 int* durations, /**< array of durations */
10134 int hmin, /**< left bound of time axis to be considered (including hmin) */
10135 int hmax, /**< right bound of time axis to be considered (not including hmax) */
10136 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10137 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10138 SCIP_CONS* cons, /**< underlying constraint, or NULL */
10139 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10140 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10141 int* nchgsides, /**< pointer to store the number of changed sides */
10142 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10143 )
10144{
10145 SCIP_Real* downimpllbs;
10146 SCIP_Real* downimplubs;
10147 SCIP_Real* downproplbs;
10148 SCIP_Real* downpropubs;
10149 SCIP_Real* upimpllbs;
10150 SCIP_Real* upimplubs;
10151 SCIP_Real* upproplbs;
10152 SCIP_Real* uppropubs;
10153
10154 int firstmaxlst;
10155 int secondmaxlst;
10156 int v;
10157
10158 /* get temporary memory for storing probing results needed for step (4) and (5) */
10159 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10160 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10161 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10162 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10163 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10164 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10165 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10166 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10167
10168 assert(scip != NULL);
10169 assert(nvars > 1);
10170 assert(cons != NULL);
10171
10172 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10173
10174 firstmaxlst = INT_MIN;
10175 secondmaxlst = INT_MIN;
10176
10177 /* compute the two largest latest start times; which are needed for step (5) */
10178 for( v = 0; v < nvars; ++v )
10179 {
10180 int lst;
10181
10183
10184 if( lst > firstmaxlst )
10185 {
10186 secondmaxlst = firstmaxlst;
10187 firstmaxlst = lst;
10188 }
10189 else if( lst > secondmaxlst )
10190 secondmaxlst = lst;
10191 }
10192
10193 /* loop over all jobs and check if one of the 5 reductions can be applied */
10194 for( v = 0; v < nvars; ++v )
10195 {
10196 SCIP_VAR* var;
10197 int duration;
10198
10199 int alternativeub;
10200 int maxlst;
10201 int est;
10202 int ect;
10203 int lst;
10204
10205 var = vars[v];
10206 assert(var != NULL);
10207
10208 duration = durations[v];
10209 assert(duration > 0);
10210
10211 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10212 * time (lct)
10213 */
10215 ect = est + duration;
10217
10218 /* compute the latest start time of all remaining jobs */
10219 if( lst == firstmaxlst )
10220 maxlst = secondmaxlst;
10221 else
10222 maxlst = firstmaxlst;
10223
10224 /* compute potential alternative upper bound (step (4) and (5)) */
10225 alternativeub = MIN(hmax - 1, maxlst) - duration;
10226 alternativeub = MAX(alternativeub, hmin);
10227
10228 if( est >= hmax )
10229 {
10230 /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10231 * cumulative condition
10232 */
10233 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10234 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10235
10236 /* mark variable to be irrelevant */
10237 irrelevants[v] = TRUE;
10238
10239 /* for the statistic we count the number of jobs which are irrelevant */
10241 }
10242 else if( ect >= hmax && SCIPconsIsChecked(cons) )
10243 {
10244 assert(downlocks != NULL);
10245 assert(uplocks != NULL);
10246
10247 /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10248 * so the up lock can be omitted
10249 */
10250
10251 if( !downlocks[v] )
10252 {
10253 /* the variables has no down lock and we can also remove the up lock;
10254 * => lst <= hmin and ect >= hmax
10255 * => remove job and reduce capacity by the demand of that job
10256 */
10257 SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10258 SCIPvarGetName(var), est, lst, duration);
10259
10260 /* mark variable to be irrelevant */
10261 irrelevants[v] = TRUE;
10262
10263 /* for the statistic we count the number of jobs which always run during the effective horizon */
10265 }
10266
10267 if( uplocks[v] )
10268 {
10269 SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10270 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10271
10272 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10273 uplocks[v] = FALSE;
10274 (*nchgsides)++;
10275
10276 /* for the statistic we count the number of removed locks */
10278 }
10279 }
10280 else if( lst >= hmax )
10281 {
10282 /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10283 * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10284 * removed form the cumulative condition after it was fixed to its latest start time
10285 */
10286
10287 /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10288 * bound
10289 */
10290 if( uplocks != NULL && SCIPconsIsChecked(cons) )
10291 {
10292 /* fix integer start time variable if possible to its upper bound */
10293 SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10294 }
10295
10296 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10297 {
10298 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10299 SCIPvarGetName(var), est, lst, duration);
10300
10301 /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10302 assert(boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10303
10304 /* mark variable to be irrelevant */
10305 irrelevants[v] = TRUE;
10306
10307 /* for the statistic we count the number of jobs which are dual fixed */
10309 }
10310 }
10311 else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10312 {
10313 assert(uplocks != NULL);
10314
10315 /* check step (4) and (5) */
10316
10317 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10318 * is in favor of rounding the variable down
10319 */
10320 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10321 {
10322 SCIP_Bool roundable;
10323
10324 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10325
10326 if( roundable )
10327 {
10328 if( alternativeub < est )
10329 {
10330 SCIP_Bool infeasible;
10331 SCIP_Bool fixed;
10332
10333 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10334 assert(!infeasible);
10335 assert(fixed);
10336
10337 (*nfixedvars)++;
10338
10339 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10340 * constraints
10341 */
10343 }
10344 else
10345 {
10346 SCIP_Bool success;
10347
10348 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10349 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10350 * in infeasible we can apply the dual reduction; otherwise we do nothing
10351 */
10352 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10353 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10354 nfixedvars, &success, cutoff) );
10355
10356 if( success )
10357 {
10359 }
10360 }
10361 }
10362 }
10363 }
10364 }
10365
10366 /* free temporary memory */
10367 SCIPfreeBufferArray(scip, &uppropubs);
10368 SCIPfreeBufferArray(scip, &upproplbs);
10369 SCIPfreeBufferArray(scip, &upimplubs);
10370 SCIPfreeBufferArray(scip, &upimpllbs);
10371 SCIPfreeBufferArray(scip, &downpropubs);
10372 SCIPfreeBufferArray(scip, &downproplbs);
10373 SCIPfreeBufferArray(scip, &downimplubs);
10374 SCIPfreeBufferArray(scip, &downimpllbs);
10375
10376 return SCIP_OKAY;
10377}
10378
10379/** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10380static
10382 SCIP* scip, /**< SCIP data structure */
10383 SCIP_CONS* cons, /**< cumulative constraint */
10384 int* nfixedvars, /**< pointer to store the number of fixed variables */
10385 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10386 int* nchgsides, /**< pointer to store the number of changed sides */
10387 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10388 )
10389{
10390 SCIP_CONSDATA* consdata;
10391 SCIP_Bool* irrelevants;
10392 int nvars;
10393 int v;
10394
10395 assert(scip != NULL);
10396 assert(cons != NULL);
10397 assert(!(*cutoff));
10398
10399 consdata = SCIPconsGetData(cons);
10400 assert(consdata != NULL);
10401
10402 nvars = consdata->nvars;
10403
10404 if( nvars <= 1 )
10405 return SCIP_OKAY;
10406
10407 SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10408 BMSclearMemoryArray(irrelevants, nvars);
10409
10410 /* presolve constraint form the earlier start time point of view */
10411 SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10412 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10413 irrelevants, nfixedvars, nchgsides, cutoff) );
10414
10415 /* presolve constraint form the latest completion time point of view */
10416 SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10417 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10418 irrelevants, nfixedvars, nchgsides, cutoff) );
10419
10420 /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10421 * order to ensure a correct behaviour
10422 */
10423 for( v = nvars-1; v >= 0; --v )
10424 {
10425 if( irrelevants[v] )
10426 {
10427 SCIP_VAR* var;
10428 int ect;
10429 int lst;
10430
10431 var = consdata->vars[v];
10432 assert(var != NULL);
10433
10434 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10436
10437 /* check if the jobs runs completely during the effective horizon */
10438 if( lst <= consdata->hmin && ect >= consdata->hmax )
10439 {
10440 if( consdata->capacity < consdata->demands[v] )
10441 {
10442 *cutoff = TRUE;
10443 break;
10444 }
10445
10446 consdata->capacity -= consdata->demands[v];
10447 consdata->varbounds = FALSE;
10448 }
10449
10450 SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10451 (*nchgcoefs)++;
10452 }
10453 }
10454
10455 SCIPfreeBufferArray(scip, &irrelevants);
10456
10457 return SCIP_OKAY;
10458}
10459
10460/** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10461static
10463 SCIP* scip, /**< SCIP data structure */
10464 SCIP_CONSDATA* consdata, /**< constraint data */
10465 int* startindices, /**< permutation with rspect to the start times */
10466 int curtime, /**< current point in time */
10467 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10468 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10469 SCIP_Longint** demands, /**< pointer to array storing the demands */
10470 int* ndemands /**< pointer to store the number of different demands */
10471 )
10472{
10473 int startindex;
10474 int ncountedvars;
10475
10476 assert(demands != NULL);
10477 assert(ndemands != NULL);
10478
10479 ncountedvars = 0;
10480 startindex = nstarted - 1;
10481
10482 *ndemands = 0;
10483
10484 /* search for the (nstarted - nfinished) jobs which are active at curtime */
10485 while( nstarted - nfinished > ncountedvars )
10486 {
10487 SCIP_VAR* var;
10488 int endtime;
10489 int varidx;
10490
10491 /* collect job information */
10492 varidx = startindices[startindex];
10493 assert(varidx >= 0 && varidx < consdata->nvars);
10494
10495 var = consdata->vars[varidx];
10496 assert(var != NULL);
10497
10498 endtime = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10499
10500 /* check the end time of this job is larger than the curtime; in this case the job is still running */
10501 if( endtime > curtime )
10502 {
10503 if( consdata->demands[varidx] < consdata->capacity )
10504 {
10505 (*demands)[*ndemands] = consdata->demands[varidx];
10506 (*ndemands)++;
10507 }
10508 ncountedvars++;
10509 }
10510
10511 startindex--;
10512 }
10513}
10514
10515/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10516 * constraint
10517 */
10518static
10520 SCIP* scip, /**< SCIP data structure */
10521 SCIP_CONS* cons, /**< constraint to be checked */
10522 int* startindices, /**< permutation with rspect to the start times */
10523 int curtime, /**< current point in time */
10524 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10525 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10526 int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10527 )
10528{
10529 SCIP_CONSDATA* consdata;
10530 SCIP_Longint* demands;
10531 SCIP_Real* profits;
10532 int* items;
10533 int ndemands;
10534 SCIP_Bool success;
10535 SCIP_Real solval;
10536 int j;
10537 assert(nstarted > nfinished);
10538
10539 consdata = SCIPconsGetData(cons);
10540 assert(consdata != NULL);
10541 assert(consdata->nvars > 0);
10542 assert(consdata->capacity > 0);
10543
10544 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10545 ndemands = 0;
10546
10547 /* get demand array to initialize knapsack problem */
10548 collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10549
10550 /* create array for profits */
10551 SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10552 SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10553 for( j = 0; j < ndemands; ++j )
10554 {
10555 profits[j] = (SCIP_Real) demands[j];
10556 items[j] = j;/* this is only a dummy value*/
10557 }
10558
10559 /* solve knapsack problem and get maximum capacity usage <= capacity */
10560 SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10561 items, NULL, NULL, NULL, NULL, &solval, &success) );
10562
10563 assert(SCIPisFeasIntegral(scip, solval));
10564
10565 /* store result */
10566 *bestcapacity = boundedConvertRealToInt(scip, solval);
10567
10568 SCIPfreeBufferArray(scip, &items);
10569 SCIPfreeBufferArray(scip, &profits);
10570 SCIPfreeBufferArray(scip, &demands);
10571
10572 return SCIP_OKAY;
10573}
10574
10575/** try to tighten the capacity
10576 * -- using DP for knapsack, we find the maximum possible capacity usage
10577 * -- neglects hmin and hmax, such that it is also able to check solutions globally
10578 */
10579static
10581 SCIP* scip, /**< SCIP data structure */
10582 SCIP_CONS* cons, /**< cumulative constraint */
10583 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10584 int* nchgsides /**< pointer to store the number of changed sides */
10585 )
10586{
10587 SCIP_CONSDATA* consdata;
10588 int* starttimes; /* stores when each job is starting */
10589 int* endtimes; /* stores when each job ends */
10590 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10591 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10592
10593 int nvars; /* number of activities for this constraint */
10594 int freecapacity; /* remaining capacity */
10595 int curtime; /* point in time which we are just checking */
10596 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10597
10598 int bestcapacity;
10599
10600 int j;
10601
10602 assert(scip != NULL);
10603 assert(cons != NULL);
10604 assert(nchgsides != NULL);
10605
10606 consdata = SCIPconsGetData(cons);
10607 assert(consdata != NULL);
10608
10609 nvars = consdata->nvars;
10610
10611 /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10612 if( nvars <= 1 || consdata->capacity <= 1 )
10613 return SCIP_OKAY;
10614
10615 assert(consdata->vars != NULL);
10616
10617 SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10618 SCIPconsGetName(cons), consdata->capacity);
10619
10620 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10621 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10622 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10623 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10624
10625 /* create event point arrays */
10626 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10627 starttimes, endtimes, startindices, endindices, FALSE);
10628
10629 bestcapacity = 1;
10630 endindex = 0;
10631 freecapacity = consdata->capacity;
10632
10633 /* check each startpoint of a job whether the capacity is kept or not */
10634 for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10635 {
10636 curtime = starttimes[j];
10637 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10638
10639 /* remove the capacity requirments for all job which start at the curtime */
10640 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10641
10642 /* add the capacity requirments for all job which end at the curtime */
10643 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10644
10645 assert(freecapacity <= consdata->capacity);
10646 assert(endindex <= nvars);
10647
10648 /* endindex - points to the next job which will finish */
10649 /* j - points to the last job that has been released */
10650
10651 /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10652 if( freecapacity < 0 )
10653 {
10654 int newcapacity;
10655
10656 newcapacity = 1;
10657
10658 /* get best possible upper bound on capacity usage */
10659 SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10660
10661 /* update bestcapacity */
10662 bestcapacity = MAX(bestcapacity, newcapacity);
10663 SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10664 }
10665
10666 /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10667 if( freecapacity > 0 && freecapacity != consdata->capacity )
10668 {
10669 bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10670 SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10671 }
10672
10673 /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10674 if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10675 {
10676 /* if demands[startindices[j]] == cap then exactly that job is running */
10677 SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10678 bestcapacity = consdata->capacity;
10679 break;
10680 }
10681 } /*lint --e{850}*/
10682
10683 /* free all buffer arrays */
10684 SCIPfreeBufferArray(scip, &endindices);
10685 SCIPfreeBufferArray(scip, &startindices);
10686 SCIPfreeBufferArray(scip, &endtimes);
10687 SCIPfreeBufferArray(scip, &starttimes);
10688
10689 /* check whether capacity can be tightened and whether demands need to be adjusted */
10690 if( bestcapacity < consdata->capacity )
10691 {
10692 SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10693
10694 SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10695 SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10696
10697 for( j = 0; j < nvars; ++j )
10698 {
10699 if( consdata->demands[j] == consdata->capacity )
10700 {
10701 consdata->demands[j] = bestcapacity;
10702 (*nchgcoefs)++;
10703 }
10704 }
10705
10706 consdata->capacity = bestcapacity;
10707 (*nchgsides)++;
10708
10709 SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10710
10711 consdata->varbounds = FALSE;
10712 }
10713
10714 return SCIP_OKAY;
10715}
10716
10717
10718/** tries to change coefficients:
10719 * demand_j < cap && all other parallel jobs in conflict
10720 * ==> set demand_j := cap
10721 */
10722static
10724 SCIP* scip, /**< SCIP data structure */
10725 SCIP_CONS* cons, /**< cumulative constraint */
10726 int* nchgcoefs /**< pointer to count total number of changed coefficients */
10727 )
10728{
10729 SCIP_CONSDATA* consdata;
10730 int nvars;
10731 int j;
10732 int oldnchgcoefs;
10733 int mindemand;
10734
10735 assert(scip != NULL);
10736 assert(cons != NULL);
10737 assert(nchgcoefs != NULL);
10738
10739 /* get constraint data for some parameter testings only! */
10740 consdata = SCIPconsGetData(cons);
10741 assert(consdata != NULL);
10742
10743 nvars = consdata->nvars;
10744 oldnchgcoefs = *nchgcoefs;
10745
10746 if( nvars <= 0 )
10747 return SCIP_OKAY;
10748
10749 /* PRE1:
10750 * check all jobs j whether: r_j + r_min > capacity holds
10751 * if so: adjust r_j to capacity
10752 */
10753 mindemand = consdata->demands[0];
10754 for( j = 0; j < nvars; ++j )
10755 {
10756 mindemand = MIN(mindemand, consdata->demands[j]);
10757 }
10758
10759 /*check each job */
10760 for( j = 0; j < nvars; ++j )
10761 {
10762 if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10763 {
10764 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10765 consdata->demands[j], consdata->capacity);
10766 consdata->demands[j] = consdata->capacity;
10767 (*nchgcoefs)++;
10768 }
10769 }
10770
10771 /* PRE2:
10772 * check for each job (with d_j < cap)
10773 * whether it is disjunctive to all others over the time horizon
10774 */
10775 for( j = 0; j < nvars; ++j )
10776 {
10777 SCIP_Bool chgcoef;
10778 int est_j;
10779 int lct_j;
10780 int i;
10781
10782 assert(consdata->demands[j] <= consdata->capacity);
10783
10784 if( consdata->demands[j] == consdata->capacity )
10785 continue;
10786
10787 chgcoef = TRUE;
10788
10789 est_j = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10790 lct_j = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10791
10792 for( i = 0; i < nvars; ++i )
10793 {
10794 int est_i;
10795 int lct_i;
10796
10797 if( i == j )
10798 continue;
10799
10800 est_i = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10801 lct_i = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10802
10803 if( est_i >= lct_j || est_j >= lct_i )
10804 continue;
10805
10806 if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10807 {
10808 chgcoef = FALSE;
10809 break;
10810 }
10811 }
10812
10813 if( chgcoef )
10814 {
10815 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10816 consdata->demands[j], consdata->capacity);
10817 consdata->demands[j] = consdata->capacity;
10818 (*nchgcoefs)++;
10819 }
10820 }
10821
10822 if( (*nchgcoefs) > oldnchgcoefs )
10823 {
10824 SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10825 (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10826 }
10827
10828 return SCIP_OKAY;
10829}
10830
10831#ifdef SCIP_DISABLED_CODE
10832/* The following should work, but does not seem to be tested well. */
10833
10834/** try to reformulate constraint by replacing certain jobs */
10835static
10836SCIP_RETCODE reformulateCons(
10837 SCIP* scip, /**< SCIP data structure */
10838 SCIP_CONS* cons, /**< cumulative constraint */
10839 int* naggrvars /**< pointer to store the number of aggregated variables */
10840 )
10841{
10842 SCIP_CONSDATA* consdata;
10843 int hmin;
10844 int hmax;
10845 int nvars;
10846 int v;
10847
10848 consdata = SCIPconsGetData(cons);
10849 assert(cons != NULL);
10850
10851 nvars = consdata->nvars;
10852 assert(nvars > 1);
10853
10854 hmin = consdata->hmin;
10855 hmax = consdata->hmax;
10856 assert(hmin < hmax);
10857
10858 for( v = 0; v < nvars; ++v )
10859 {
10860 SCIP_VAR* var;
10861 int duration;
10862 int est;
10863 int ect;
10864 int lst;
10865 int lct;
10866
10867 var = consdata->vars[v];
10868 assert(var != NULL);
10869
10870 duration = consdata->durations[v];
10871
10873 ect = est + duration;
10875 lct = lst + duration;
10876
10877 /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10878 assert(lst > hmin || ect < hmax);
10879
10880 if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10881 {
10882 SCIP_VAR* aggrvar;
10883 char name[SCIP_MAXSTRLEN];
10884 SCIP_Bool infeasible;
10885 SCIP_Bool redundant;
10886 SCIP_Bool aggregated;
10887 int shift;
10888
10889 shift = est - (hmin - lct + MIN(hmin, ect));
10890 assert(shift > 0);
10891 lst = hmin;
10892 duration = hmin - lct;
10893
10894 SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10895 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10896
10897 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10898 SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10900 SCIP_CALL( SCIPaddVar(scip, var) );
10901 SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10902
10903 assert(!infeasible);
10904 assert(!redundant);
10905 assert(aggregated);
10906
10907 /* replace variable */
10908 consdata->durations[v] = duration;
10909 consdata->vars[v] = aggrvar;
10910
10911 /* remove and add locks */
10912 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10913 SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10914
10915 SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10916
10917 (*naggrvars)++;
10918 }
10919 }
10920
10921 return SCIP_OKAY;
10922}
10923#endif
10924
10925/** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10926static
10928 SCIP* scip, /**< SCIP data structure */
10929 SCIP_CONS* cons, /**< cumulative constraint */
10930 int* naddconss /**< pointer to store the number of added constraints */
10931 )
10932{
10933 SCIP_CONSDATA* consdata;
10934 SCIP_VAR** vars;
10935 int* durations;
10936 int* demands;
10937 int capacity;
10938 int halfcapacity;
10939 int mindemand;
10940 int nvars;
10941 int v;
10942
10943 consdata = SCIPconsGetData(cons);
10944 assert(consdata != NULL);
10945
10946 capacity = consdata->capacity;
10947
10948 if( capacity == 1 )
10949 return SCIP_OKAY;
10950
10951 SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10952 SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10953 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10954
10955 halfcapacity = capacity / 2;
10956 mindemand = consdata->capacity;
10957 nvars = 0;
10958
10959 /* collect all jobs with demand larger than half of the capacity */
10960 for( v = 0; v < consdata->nvars; ++v )
10961 {
10962 if( consdata->demands[v] > halfcapacity )
10963 {
10964 vars[nvars] = consdata->vars[v];
10965 demands[nvars] = 1;
10966 durations[nvars] = consdata->durations[v];
10967 nvars++;
10968
10969 mindemand = MIN(mindemand, consdata->demands[v]);
10970 }
10971 }
10972
10973 if( nvars > 0 )
10974 {
10975 /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
10976 * job is still to large to be scheduled in parallel
10977 */
10978 for( v = 0; v < consdata->nvars; ++v )
10979 {
10980 if( consdata->demands[v] > halfcapacity )
10981 continue;
10982
10983 if( mindemand + consdata->demands[v] > capacity )
10984 {
10985 demands[nvars] = 1;
10986 durations[nvars] = consdata->durations[v];
10987 vars[nvars] = consdata->vars[v];
10988 nvars++;
10989
10990 /* @todo create one cumulative constraint and look for another small demand */
10991 break;
10992 }
10993 }
10994
10995 /* creates cumulative constraint and adds it to problem */
10996 SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
10998 (*naddconss)++;
10999 }
11000
11001 SCIPfreeBufferArray(scip, &demands);
11002 SCIPfreeBufferArray(scip, &durations);
11003 SCIPfreeBufferArray(scip, &vars);
11004
11005 return SCIP_OKAY;
11006}
11007
11008/** presolve given constraint */
11009static
11011 SCIP* scip, /**< SCIP data structure */
11012 SCIP_CONS* cons, /**< cumulative constraint */
11013 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11014 SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11015 int* nfixedvars, /**< pointer to store the number of fixed variables */
11016 int* nchgbds, /**< pointer to store the number of changed bounds */
11017 int* ndelconss, /**< pointer to store the number of deleted constraints */
11018 int* naddconss, /**< pointer to store the number of added constraints */
11019 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11020 int* nchgsides, /**< pointer to store the number of changed sides */
11021 SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11022 SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11023 )
11024{
11025 assert(!SCIPconsIsDeleted(cons));
11026
11027 /* only perform dual reductions on model constraints */
11028 if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11029 {
11030 /* computes the effective horizon and checks if the constraint can be decomposed */
11031 SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11032
11033 if( SCIPconsIsDeleted(cons) )
11034 return SCIP_OKAY;
11035
11036 /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11037 * fixings (dual reductions)
11038 */
11039 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11040 {
11041 SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11042
11043 if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11044 return SCIP_OKAY;
11045 }
11046
11047 SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11048
11049 if( *cutoff || SCIPconsIsDeleted(cons) )
11050 return SCIP_OKAY;
11051 }
11052
11053 /* remove jobs which have a demand larger than the capacity */
11054 SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11055 assert((*cutoff) || checkDemands(scip, cons));
11056
11057 if( *cutoff )
11058 return SCIP_OKAY;
11059
11060 if( conshdlrdata->normalize )
11061 {
11062 /* divide demands by their greatest common divisor */
11063 normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11064 }
11065
11066 /* delete constraint with one job */
11067 SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11068
11069 if( *cutoff || SCIPconsIsDeleted(cons) )
11070 return SCIP_OKAY;
11071
11072 if( conshdlrdata->coeftightening )
11073 {
11074 /* try to tighten the capacity */
11075 SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11076
11077 /* try to tighten the coefficients */
11078 SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11079 }
11080
11081 assert(checkDemands(scip, cons) || *cutoff);
11082
11083#ifdef SCIP_DISABLED_CODE
11084 /* The following should work, but does not seem to be tested well. */
11085 SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11086#endif
11087
11088 return SCIP_OKAY;
11089}
11090
11091/**@name TClique Graph callbacks
11092 *
11093 * @{
11094 */
11095
11096/** tclique graph data */
11097struct TCLIQUE_Graph
11098{
11099 SCIP_VAR** vars; /**< start time variables each of them is a node */
11100 SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11101 SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11102 SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11103 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11104 int* ninarcs; /**< number if in arcs for the precedence graph */
11105 int* noutarcs; /**< number if out arcs for the precedence graph */
11106 int* durations; /**< for each node the duration of the corresponding job */
11107 int nnodes; /**< number of nodes */
11108 int size; /**< size of the array */
11109};
11110
11111/** gets number of nodes in the graph */
11112static
11113TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11114{
11115 assert(tcliquegraph != NULL);
11116
11117 return tcliquegraph->nnodes;
11118}
11119
11120/** gets weight of nodes in the graph */
11121static
11122TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11123{
11124 assert(tcliquegraph != NULL);
11125
11126 return tcliquegraph->weights;
11127}
11128
11129/** returns, whether the edge (node1, node2) is in the graph */
11130static
11131TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11132{
11133 assert(tcliquegraph != NULL);
11134 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11135 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11136
11137 /* check if an arc exits in the precedence graph */
11138 if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11139 return TRUE;
11140
11141 /* check if an edge exits in the non-overlapping graph */
11142 if( tcliquegraph->demandmatrix[node1][node2] )
11143 return TRUE;
11144
11145 return FALSE;
11146}
11147
11148/** selects all nodes from a given set of nodes which are adjacent to a given node
11149 * and returns the number of selected nodes
11150 */
11151static
11152TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11153{
11154 int nadjnodes;
11155 int i;
11156
11157 assert(tcliquegraph != NULL);
11158 assert(0 <= node && node < tcliquegraph->nnodes);
11159 assert(nnodes == 0 || nodes != NULL);
11160 assert(adjnodes != NULL);
11161
11162 nadjnodes = 0;
11163
11164 for( i = 0; i < nnodes; i++ )
11165 {
11166 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11167 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11168 assert(i == 0 || nodes[i-1] < nodes[i]);
11169
11170 /* check if an edge exists */
11171 if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11172 {
11173 /* current node is adjacent to given node */
11174 adjnodes[nadjnodes] = nodes[i];
11175 nadjnodes++;
11176 }
11177 }
11178
11179 return nadjnodes;
11180}
11181
11182/** generates cuts using a clique found by algorithm for maximum weight clique
11183 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11184 */
11185static
11186TCLIQUE_NEWSOL(tcliqueNewsolClique)
11187{ /*lint --e{715}*/
11188 SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11189}
11190
11191
11192/** @} */
11193
11194/** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11195 * job corresponding to variable bound variable (vlbvar)
11196 *
11197 * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11198 */
11199static
11201 SCIP* scip, /**< SCIP data structure */
11202 SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11203 SCIP_Real vlbcoef, /**< variable bound coefficient */
11204 SCIP_Real vlbconst, /**< variable bound constant */
11205 int duration /**< duration of the variable bound variable */
11206 )
11207{
11208 if( SCIPisEQ(scip, vlbcoef, 1.0) )
11209 {
11210 if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11211 {
11212 /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11213 return TRUE;
11214 }
11215 }
11216 else
11217 {
11219
11220 bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11221
11222 if( SCIPisLT(scip, vlbcoef, 1.0) )
11223 {
11224 SCIP_Real ub;
11225
11226 ub = SCIPvarGetUbLocal(vlbvar);
11227
11228 /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11229 if( SCIPisLE(scip, ub, bound) )
11230 return TRUE;
11231 }
11232 else
11233 {
11234 SCIP_Real lb;
11235
11236 assert(SCIPisGT(scip, vlbcoef, 1.0));
11237
11238 lb = SCIPvarGetLbLocal(vlbvar);
11239
11240 /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11241 if( SCIPisGE(scip, lb, bound) )
11242 return TRUE;
11243 }
11244 }
11245
11246 return FALSE;
11247}
11248
11249/** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11250 * job corresponding to variable which is bounded (var)
11251 *
11252 * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11253 */
11254static
11256 SCIP* scip, /**< SCIP data structure */
11257 SCIP_VAR* var, /**< variable which is bound from above */
11258 SCIP_Real vubcoef, /**< variable bound coefficient */
11259 SCIP_Real vubconst, /**< variable bound constant */
11260 int duration /**< duration of the variable which is bounded from above */
11261 )
11262{
11263 SCIP_Real vlbcoef;
11264 SCIP_Real vlbconst;
11265
11266 /* convert the variable upper bound into an variable lower bound */
11267 vlbcoef = 1.0 / vubcoef;
11268 vlbconst = -vubconst / vubcoef;
11269
11270 return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11271}
11272
11273/** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11274 * others an index larger than the number if active variables
11275 */
11276static
11278 SCIP* scip, /**< SCIP data structure */
11279 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11280 SCIP_VAR* var, /**< variable for which we want the index */
11281 int* idx /**< pointer to store the index */
11282 )
11283{
11284 (*idx) = SCIPvarGetProbindex(var);
11285
11286 if( (*idx) == -1 )
11287 {
11288 if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11289 {
11290 (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11291 }
11292 else
11293 {
11294 int pos;
11295 int v;
11296
11297 /**@todo we might want to add the aggregation path to graph */
11298
11299 /* check if we have to realloc memory */
11300 if( tcliquegraph->size == tcliquegraph->nnodes )
11301 {
11302 int size;
11303
11304 size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11305 tcliquegraph->size = size;
11306
11307 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11308 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11309 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11310 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11311 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11312
11313 for( v = 0; v < tcliquegraph->nnodes; ++v )
11314 {
11315 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11316 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11317 }
11318 }
11319 assert(tcliquegraph->nnodes < tcliquegraph->size);
11320
11321 pos = tcliquegraph->nnodes;
11322 assert(pos >= 0);
11323
11324 tcliquegraph->durations[pos] = 0;
11325 tcliquegraph->weights[pos] = 0;
11326 tcliquegraph->vars[pos] = var;
11327
11328 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11329 BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11330
11331 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11332 BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11333
11334 SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11335
11336 tcliquegraph->nnodes++;
11337
11338 for( v = 0; v < tcliquegraph->nnodes; ++v )
11339 {
11340 tcliquegraph->precedencematrix[v][pos] = 0;
11341 tcliquegraph->demandmatrix[v][pos] = 0;
11342 }
11343
11344 (*idx) = tcliquegraph->nnodes;
11345 }
11346 }
11347 else
11348 {
11349 assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11350 }
11351
11352 assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11353
11354 return SCIP_OKAY;
11355}
11356
11357/** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11358 *
11359 * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11360 * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11361 *
11362 * (i) b = 1 and c >= d
11363 * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11364 * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11365 *
11366 */
11367static
11369 SCIP* scip, /**< SCIP data structure */
11370 TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11371 )
11372{
11373 SCIP_VAR** vars;
11374 int nvars;
11375 int v;
11376
11377 vars = SCIPgetVars(scip);
11378 nvars = SCIPgetNVars(scip);
11379
11380 /* try to project each arc of the variable bound graph to precedence condition */
11381 for( v = 0; v < nvars; ++v )
11382 {
11383 SCIP_VAR** vbdvars;
11384 SCIP_VAR* var;
11385 SCIP_Real* vbdcoefs;
11386 SCIP_Real* vbdconsts;
11387 int nvbdvars;
11388 int idx1;
11389 int b;
11390
11391 var = vars[v];
11392 assert(var != NULL);
11393
11394 SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11395 assert(idx1 >= 0);
11396
11397 if( tcliquegraph->durations[idx1] == 0 )
11398 continue;
11399
11400 vbdvars = SCIPvarGetVlbVars(var);
11401 vbdcoefs = SCIPvarGetVlbCoefs(var);
11402 vbdconsts = SCIPvarGetVlbConstants(var);
11403 nvbdvars = SCIPvarGetNVlbs(var);
11404
11405 for( b = 0; b < nvbdvars; ++b )
11406 {
11407 int idx2;
11408
11409 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11410 assert(idx2 >= 0);
11411
11412 if( tcliquegraph->durations[idx2] == 0 )
11413 continue;
11414
11415 if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11416 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11417 }
11418
11419 vbdvars = SCIPvarGetVubVars(var);
11420 vbdcoefs = SCIPvarGetVubCoefs(var);
11421 vbdconsts = SCIPvarGetVubConstants(var);
11422 nvbdvars = SCIPvarGetNVubs(var);
11423
11424 for( b = 0; b < nvbdvars; ++b )
11425 {
11426 int idx2;
11427
11428 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11429 assert(idx2 >= 0);
11430
11431 if( tcliquegraph->durations[idx2] == 0 )
11432 continue;
11433
11434 if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11435 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11436 }
11437
11438 for( b = v+1; b < nvars; ++b )
11439 {
11440 int idx2;
11441
11442 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11443 assert(idx2 >= 0);
11444
11445 if( tcliquegraph->durations[idx2] == 0 )
11446 continue;
11447
11448 /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11449 if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11450 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11451
11452 /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11453 if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11454 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11455 }
11456 }
11457
11458 return SCIP_OKAY;
11459}
11460
11461/** compute the transitive closer of the given graph and the number of in and out arcs */
11462static
11464 SCIP_Bool** adjmatrix, /**< adjacent matrix */
11465 int* ninarcs, /**< array to store the number of in arcs */
11466 int* noutarcs, /**< array to store the number of out arcs */
11467 int nnodes /**< number if nodes */
11468 )
11469{
11470 int i;
11471 int j;
11472 int k;
11473
11474 for( i = 0; i < nnodes; ++i )
11475 {
11476 for( j = 0; j < nnodes; ++j )
11477 {
11478 if( adjmatrix[i][j] )
11479 {
11480 ninarcs[j]++;
11481 noutarcs[i]++;
11482
11483 for( k = 0; k < nnodes; ++k )
11484 {
11485 if( adjmatrix[j][k] )
11486 adjmatrix[i][k] = TRUE;
11487 }
11488 }
11489 }
11490 }
11491}
11492
11493/** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11494static
11496 SCIP* scip, /**< SCIP data structure */
11497 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11498 SCIP_CONS** conss, /**< array of cumulative constraints */
11499 int nconss /**< number of cumulative constraints */
11500 )
11501{
11502 int c;
11503
11504 /* use the cumulative constraints to initialize the none overlapping graph */
11505 for( c = 0; c < nconss; ++c )
11506 {
11507 SCIP_CONSDATA* consdata;
11508 SCIP_VAR** vars;
11509 int* demands;
11510 int capacity;
11511 int nvars;
11512 int i;
11513
11514 consdata = SCIPconsGetData(conss[c]);
11515 assert(consdata != NULL);
11516
11517 vars = consdata->vars;
11518 demands = consdata->demands;
11519
11520 nvars = consdata->nvars;
11521 capacity = consdata->capacity;
11522
11523 SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11524
11525 /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11526 for( i = 0; i < nvars; ++i )
11527 {
11528 int idx1;
11529 int j;
11530
11531 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11532 assert(idx1 >= 0);
11533
11534 if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11535 continue;
11536
11537 for( j = i+1; j < nvars; ++j )
11538 {
11539 assert(consdata->durations[j] > 0);
11540
11541 if( demands[i] + demands[j] > capacity )
11542 {
11543 int idx2;
11544 int est1;
11545 int est2;
11546 int lct1;
11547 int lct2;
11548
11549 /* check if the effective horizon is large enough */
11552
11553 /* at least one of the jobs needs to start at hmin or later */
11554 if( est1 < consdata->hmin && est2 < consdata->hmin )
11555 continue;
11556
11557 lct1 = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11558 lct2 = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11559
11560 /* at least one of the jobs needs to finish not later then hmin */
11561 if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11562 continue;
11563
11564 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11565 assert(idx2 >= 0);
11566 assert(idx1 != idx2);
11567
11568 if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11569 continue;
11570
11571 SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11572
11573 assert(tcliquegraph->durations[idx1] > 0);
11574 assert(tcliquegraph->durations[idx2] > 0);
11575
11576 tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11577 tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11578 }
11579 }
11580 }
11581 }
11582
11583 return SCIP_OKAY;
11584}
11585
11586/** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11587 * of jobs cannot run in parallel
11588 */
11589static
11591 SCIP* scip, /**< SCIP data structure */
11592 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11593 SCIP_CONS** conss, /**< array of cumulative constraints */
11594 int nconss /**< number of cumulative constraints */
11595 )
11596{
11597 assert(scip != NULL);
11598 assert(tcliquegraph != NULL);
11599
11600 /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11601 SCIP_CALL( projectVbd(scip, tcliquegraph) );
11602
11603 /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11604 transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11605
11606 /* constraints non-overlapping graph */
11607 SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11608
11609 return SCIP_OKAY;
11610}
11611
11612/** create cumulative constraint from conflict set */
11613static
11615 SCIP* scip, /**< SCIP data structure */
11616 const char* name, /**< constraint name */
11617 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11618 int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11619 int ncliquenodes /**< number of nodes in the clique */
11620 )
11621{
11622 SCIP_CONS* cons;
11623 SCIP_VAR** vars;
11624 int* durations;
11625 int* demands;
11626 int v;
11627
11628 SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11629 SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11630 SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11631
11632 SCIPsortInt(cliquenodes, ncliquenodes);
11633
11634 /* collect variables, durations, and demands */
11635 for( v = 0; v < ncliquenodes; ++v )
11636 {
11637 durations[v] = tcliquegraph->durations[cliquenodes[v]];
11638 assert(durations[v] > 0);
11639 demands[v] = 1;
11640 vars[v] = tcliquegraph->vars[cliquenodes[v]];
11641 }
11642
11643 /* create (unary) cumulative constraint */
11644 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11646
11647 SCIP_CALL( SCIPaddCons(scip, cons) );
11648 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11649
11650 /* free buffers */
11651 SCIPfreeBufferArray(scip, &demands);
11652 SCIPfreeBufferArray(scip, &durations);
11653 SCIPfreeBufferArray(scip, &vars);
11654
11655 return SCIP_OKAY;
11656}
11657
11658/** search for cumulative constrainst */
11659static
11661 SCIP* scip, /**< SCIP data structure */
11662 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11663 int* naddconss /**< pointer to store the number of added constraints */
11664 )
11665{
11666 TCLIQUE_STATUS tcliquestatus;
11667 SCIP_Bool* precedencerow;
11668 SCIP_Bool* precedencecol;
11669 SCIP_Bool* demandrow;
11670 SCIP_Bool* demandcol;
11671 SCIP_HASHTABLE* covered;
11672 int* cliquenodes;
11673 int ncliquenodes;
11674 int cliqueweight;
11675 int ntreenodes;
11676 int nnodes;
11677 int nconss;
11678 int v;
11679
11680 nnodes = tcliquegraph->nnodes;
11681 nconss = 0;
11682
11683 /* initialize the weight of each job with its duration */
11684 for( v = 0; v < nnodes; ++v )
11685 {
11686 tcliquegraph->weights[v] = tcliquegraph->durations[v];
11687 }
11688
11689 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11690 SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11691 SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11692 SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11693 SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11694
11695 /* create a hash table to store all start time variables which are already covered by at least one clique */
11697 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11698
11699 /* for each variables/job we are ... */
11700 for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11701 {
11702 char name[SCIP_MAXSTRLEN];
11703 int c;
11704
11705 /* jobs with zero durations are skipped */
11706 if( tcliquegraph->durations[v] == 0 )
11707 continue;
11708
11709 /* check if the start time variable is already covered by at least one clique */
11710 if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11711 continue;
11712
11713 SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11714
11715 /* temporarily remove the connection via the precedence graph */
11716 for( c = 0; c < nnodes; ++c )
11717 {
11718 precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11719 precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11720
11721 demandrow[c] = tcliquegraph->demandmatrix[v][c];
11722 demandcol[c] = tcliquegraph->demandmatrix[c][v];
11723
11724 tcliquegraph->precedencematrix[c][v] = FALSE;
11725 tcliquegraph->precedencematrix[v][c] = FALSE;
11726 }
11727
11728 /* find (heuristically) maximum cliques which includes node v */
11729 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11730 tcliquegraph, tcliqueNewsolClique, NULL,
11731 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11732 10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11733
11734 SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11735
11736 if( ncliquenodes == 1 )
11737 continue;
11738
11739 /* construct constraint name */
11740 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11741
11742 SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11743 nconss++;
11744
11745 /* all start time variable to covered hash table */
11746 for( c = 0; c < ncliquenodes; ++c )
11747 {
11748 SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11749 }
11750
11751 /* copy the precedence relations back */
11752 for( c = 0; c < nnodes; ++c )
11753 {
11754 tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11755 tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11756
11757 tcliquegraph->demandmatrix[v][c] = demandrow[c];
11758 tcliquegraph->demandmatrix[c][v] = demandcol[c];
11759 }
11760 }
11761
11762 SCIPhashtableFree(&covered);
11763
11764 SCIPfreeBufferArray(scip, &demandcol);
11765 SCIPfreeBufferArray(scip, &demandrow);
11766 SCIPfreeBufferArray(scip, &precedencecol);
11767 SCIPfreeBufferArray(scip, &precedencerow);
11768 SCIPfreeBufferArray(scip, &cliquenodes);
11769
11770 (*naddconss) += nconss;
11771
11772 /* for the statistic we count the number added disjunctive constraints */
11773 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11774
11775 return SCIP_OKAY;
11776}
11777
11778/** create precedence constraint (as variable bound constraint */
11779static
11781 SCIP* scip, /**< SCIP data structure */
11782 const char* name, /**< constraint name */
11783 SCIP_VAR* var, /**< variable x that has variable bound */
11784 SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11785 int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11786 )
11787{
11788 SCIP_CONS* cons;
11789
11790 /* create variable bound constraint */
11791 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11793
11795
11796 /* add constraint to problem and release it */
11797 SCIP_CALL( SCIPaddCons(scip, cons) );
11798 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11799
11800 return SCIP_OKAY;
11801}
11802
11803/** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11804static
11806 SCIP* scip, /**< SCIP data structure */
11807 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11808 int source, /**< index of the source node */
11809 int sink, /**< index of the sink node */
11810 int* naddconss /**< pointer to store the number of added constraints */
11811 )
11812{
11813 TCLIQUE_WEIGHT cliqueweight;
11814 TCLIQUE_STATUS tcliquestatus;
11815 SCIP_VAR** vars;
11816 int* cliquenodes;
11817 int nnodes;
11818 int lct;
11819 int est;
11820 int i;
11821
11822 int ntreenodes;
11823 int ncliquenodes;
11824
11825 /* check if source and sink are connencted */
11826 if( !tcliquegraph->precedencematrix[source][sink] )
11827 return SCIP_OKAY;
11828
11829 nnodes = tcliquegraph->nnodes;
11830 vars = tcliquegraph->vars;
11831
11832 /* reset the weights to zero */
11833 BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11834
11835 /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11836 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11838
11839 /* weight all jobs which run for sure between source and sink with their duration */
11840 for( i = 0; i < nnodes; ++i )
11841 {
11842 SCIP_VAR* var;
11843 int duration;
11844
11845 var = vars[i];
11846 assert(var != NULL);
11847
11848 duration = tcliquegraph->durations[i];
11849
11850 if( i == source || i == sink )
11851 {
11852 /* source and sink are not weighted */
11853 tcliquegraph->weights[i] = 0;
11854 }
11855 else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11856 {
11857 /* job i runs after source and before sink */
11858 tcliquegraph->weights[i] = duration;
11859 }
11860 else if( lct <= boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var))
11861 && est >= boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11862 {
11863 /* job i run in between due the bounds of the start time variables */
11864 tcliquegraph->weights[i] = duration;
11865 }
11866 else
11867 tcliquegraph->weights[i] = 0;
11868 }
11869
11870 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11871
11872 /* find (heuristically) maximum cliques */
11873 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11874 tcliquegraph, tcliqueNewsolClique, NULL,
11875 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11876 10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11877
11878 if( ncliquenodes > 1 )
11879 {
11880 char name[SCIP_MAXSTRLEN];
11881 int distance;
11882
11883 /* construct constraint name */
11884 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11885
11886 /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11887 * duration of the source job
11888 */
11889 distance = cliqueweight + tcliquegraph->durations[source];
11890
11891 SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11892 (*naddconss)++;
11893 }
11894
11895 SCIPfreeBufferArray(scip, &cliquenodes);
11896
11897 return SCIP_OKAY;
11898}
11899
11900/** search for precedence constraints
11901 *
11902 * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11903 * corresponding two jobs
11904 */
11905static
11907 SCIP* scip, /**< SCIP data structure */
11908 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11909 int* naddconss /**< pointer to store the number of added constraints */
11910 )
11911{
11912 int* sources;
11913 int* sinks;
11914 int nconss;
11915 int nnodes;
11916 int nsources;
11917 int nsinks;
11918 int i;
11919
11920 nnodes = tcliquegraph->nnodes;
11921 nconss = 0;
11922
11923 nsources = 0;
11924 nsinks = 0;
11925
11928
11929 /* first collect all sources and sinks */
11930 for( i = 0; i < nnodes; ++i )
11931 {
11932 if( tcliquegraph->ninarcs[i] == 0 )
11933 {
11934 sources[nsources] = i;
11935 nsources++;
11936 }
11937
11938 if( tcliquegraph->noutarcs[i] == 0 )
11939 {
11940 sinks[nsinks] = i;
11941 nsinks++;
11942 }
11943 }
11944
11945 /* compute for each node a minimum distance to each sources and each sink */
11946 for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
11947 {
11948 int j;
11949
11950 for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
11951 {
11952 SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
11953 }
11954
11955 for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
11956 {
11957 SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
11958 }
11959 }
11960
11961 (*naddconss) += nconss;
11962
11963 /* for the statistic we count the number added variable constraints */
11964 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
11965
11966 SCIPfreeBufferArray(scip, &sinks);
11967 SCIPfreeBufferArray(scip, &sources);
11968
11969 return SCIP_OKAY;
11970}
11971
11972/** initialize the assumed durations for each variable */
11973static
11975 SCIP* scip, /**< SCIP data structure */
11976 TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
11977 SCIP_CONS** conss, /**< cumulative constraints */
11978 int nconss /**< number of cumulative constraints */
11979 )
11980{
11981 int c;
11982
11983 /* use the cumulative structure to define the duration we are using for each job */
11984 for( c = 0; c < nconss; ++c )
11985 {
11986 SCIP_CONSDATA* consdata;
11987 SCIP_VAR** vars;
11988 int nvars;
11989 int v;
11990
11991 consdata = SCIPconsGetData(conss[c]);
11992 assert(consdata != NULL);
11993
11994 vars = consdata->vars;
11995 nvars = consdata->nvars;
11996
11997 for( v = 0; v < nvars; ++v )
11998 {
11999 int idx;
12000
12001 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12002 assert(idx >= 0);
12003
12004 /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12005 * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12006 * general this is not the case. Therefore, the question would be which duration should be used?
12007 */
12008 tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12009 assert(tcliquegraph->durations[idx] > 0);
12010 }
12011 }
12012
12013 return SCIP_OKAY;
12014}
12015
12016/** create tclique graph */
12017static
12019 SCIP* scip, /**< SCIP data structure */
12020 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12021 )
12022{
12023 SCIP_VAR** vars;
12024 SCIP_HASHMAP* varmap;
12025 SCIP_Bool** precedencematrix;
12026 SCIP_Bool** demandmatrix;
12027 int* ninarcs;
12028 int* noutarcs;
12029 int* durations;
12030 int* weights;
12031 int nvars;
12032 int v;
12033
12034 vars = SCIPgetVars(scip);
12035 nvars = SCIPgetNVars(scip);
12036
12037 /* allocate memory for the tclique graph data structure */
12038 SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12039
12040 /* create the variable mapping hash map */
12041 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12042
12043 /* each active variables get a node in the graph */
12044 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12045
12046 /* allocate memory for the projected variables bound graph and the none overlapping graph */
12047 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12048 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12049
12050 /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12051 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12052 BMSclearMemoryArray(weights, nvars);
12053
12054 /* array to store the number of in arc of the precedence graph */
12055 SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12056 BMSclearMemoryArray(ninarcs, nvars);
12057
12058 /* array to store the number of out arc of the precedence graph */
12059 SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12060 BMSclearMemoryArray(noutarcs, nvars);
12061
12062 /* array to store the used duration for each node */
12063 SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12064 BMSclearMemoryArray(durations, nvars);
12065
12066 for( v = 0; v < nvars; ++v )
12067 {
12068 SCIP_VAR* var;
12069
12070 var = vars[v];
12071 assert(var != NULL);
12072
12073 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12074 BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12075
12076 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12077 BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12078
12079 /* insert all active variables into the garph */
12080 assert(SCIPvarGetProbindex(var) == v);
12081 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12082 }
12083
12084 (*tcliquegraph)->nnodes = nvars;
12085 (*tcliquegraph)->varmap = varmap;
12086 (*tcliquegraph)->precedencematrix = precedencematrix;
12087 (*tcliquegraph)->demandmatrix = demandmatrix;
12088 (*tcliquegraph)->weights = weights;
12089 (*tcliquegraph)->ninarcs = ninarcs;
12090 (*tcliquegraph)->noutarcs = noutarcs;
12091 (*tcliquegraph)->durations = durations;
12092 (*tcliquegraph)->size = nvars;
12093
12094 return SCIP_OKAY;
12095}
12096
12097/** frees the tclique graph */
12098static
12100 SCIP* scip, /**< SCIP data structure */
12101 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12102 )
12103{
12104 int v;
12105
12106 for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12107 {
12108 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12109 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12110 }
12111
12112 SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12113 SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12114 SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12115 SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12116 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12117 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12118 SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12119 SCIPhashmapFree(&(*tcliquegraph)->varmap);
12120
12121 SCIPfreeBuffer(scip, tcliquegraph);
12122}
12123
12124/** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12125 * constrains (disjunctive constraint)
12126 */
12127static
12129 SCIP* scip, /**< SCIP data structure */
12130 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12131 SCIP_CONS** conss, /**< array of cumulative constraints */
12132 int nconss, /**< number of cumulative constraints */
12133 int* naddconss /**< pointer to store the number of added constraints */
12134 )
12135{
12136 TCLIQUE_GRAPH* tcliquegraph;
12137
12138 /* create tclique graph */
12139 SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12140
12141 /* define for each job a duration */
12142 SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12143
12144 /* constuct incompatibility graph */
12145 SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12146
12147 /* search for new precedence constraints */
12148 if( conshdlrdata->detectvarbounds )
12149 {
12150 SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12151 }
12152
12153 /* search for new cumulative constraints */
12154 if( conshdlrdata->detectdisjunctive )
12155 {
12156 SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12157 }
12158
12159 /* free tclique graph data structure */
12160 freeTcliqueGraph(scip, &tcliquegraph);
12161
12162 return SCIP_OKAY;
12163}
12164
12165/** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12166static
12168 SCIP_CONSDATA* consdata /**< cumulative constraint data */
12169 )
12170{
12171 SCIP_VAR** vars;
12172 int nvars;
12173 int v;
12174
12175 if( consdata->validsignature )
12176 return;
12177
12178 vars = consdata->vars;
12179 nvars = consdata->nvars;
12180
12181 for( v = 0; v < nvars; ++v )
12182 {
12183 consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12184 }
12185
12186 consdata->validsignature = TRUE;
12187}
12188
12189/** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12190static
12192{ /*lint --e{715}*/
12193 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12194
12195 assert(consdata != NULL);
12196 assert(0 <= ind1 && ind1 < consdata->nvars);
12197 assert(0 <= ind2 && ind2 < consdata->nvars);
12198
12199 return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12200}
12201
12202/** run a pairwise comparison */
12203static
12205 SCIP* scip, /**< SCIP data structure */
12206 SCIP_CONS** conss, /**< array of cumulative constraints */
12207 int nconss, /**< number of cumulative constraints */
12208 int* ndelconss /**< pointer to store the number of deletedconstraints */
12209 )
12210{
12211 int i;
12212 int j;
12213
12214 for( i = 0; i < nconss; ++i )
12215 {
12216 SCIP_CONSDATA* consdata0;
12217 SCIP_CONS* cons0;
12218
12219 cons0 = conss[i];
12220 assert(cons0 != NULL);
12221
12222 consdata0 = SCIPconsGetData(cons0);
12223 assert(consdata0 != NULL);
12224
12225 consdataCalcSignature(consdata0);
12226 assert(consdata0->validsignature);
12227
12228 for( j = i+1; j < nconss; ++j )
12229 {
12230 SCIP_CONSDATA* consdata1;
12231 SCIP_CONS* cons1;
12232
12233 cons1 = conss[j];
12234 assert(cons1 != NULL);
12235
12236 consdata1 = SCIPconsGetData(cons1);
12237 assert(consdata1 != NULL);
12238
12239 if( consdata0->capacity != consdata1->capacity )
12240 continue;
12241
12242 consdataCalcSignature(consdata1);
12243 assert(consdata1->validsignature);
12244
12245 if( (consdata1->signature & (~consdata0->signature)) == 0 )
12246 {
12247 SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12248 SCIPswapPointers((void**)&cons0, (void**)&cons1);
12249 assert((consdata0->signature & (~consdata1->signature)) == 0);
12250 }
12251
12252 if( (consdata0->signature & (~consdata1->signature)) == 0 )
12253 {
12254 int* perm0;
12255 int* perm1;
12256 int v0;
12257 int v1;
12258
12259 if( consdata0->nvars > consdata1->nvars )
12260 continue;
12261
12262 if( consdata0->hmin < consdata1->hmin )
12263 continue;
12264
12265 if( consdata0->hmax > consdata1->hmax )
12266 continue;
12267
12268 SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12269 SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12270
12271 /* call sorting method */
12272 SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12273 SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12274
12275 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12276 {
12277 SCIP_VAR* var0;
12278 SCIP_VAR* var1;
12279 int idx0;
12280 int idx1;
12281 int comp;
12282
12283 idx0 = perm0[v0];
12284 idx1 = perm1[v1];
12285
12286 var0 = consdata0->vars[idx0];
12287
12288 var1 = consdata1->vars[idx1];
12289
12290 comp = SCIPvarCompare(var0, var1);
12291
12292 if( comp == 0 )
12293 {
12294 int duration0;
12295 int duration1;
12296 int demand0;
12297 int demand1;
12298
12299 demand0 = consdata0->demands[idx0];
12300 duration0 = consdata0->durations[idx0];
12301
12302 demand1 = consdata1->demands[idx1];
12303 duration1 = consdata1->durations[idx1];
12304
12305 if( demand0 != demand1 )
12306 break;
12307
12308 if( duration0 != duration1 )
12309 break;
12310
12311 v0++;
12312 v1++;
12313 }
12314 else if( comp > 0 )
12315 v1++;
12316 else
12317 break;
12318 }
12319
12320 if( v0 == consdata0->nvars )
12321 {
12322 if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12323 {
12324 initializeLocks(consdata1, TRUE);
12325 }
12326
12327 /* coverity[swapped_arguments] */
12328 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12329
12330 SCIP_CALL( SCIPdelCons(scip, cons0) );
12331 (*ndelconss)++;
12332 }
12333
12334 SCIPfreeBufferArray(scip, &perm1);
12335 SCIPfreeBufferArray(scip, &perm0);
12336 }
12337 }
12338 }
12339
12340 return SCIP_OKAY;
12341}
12342
12343/** strengthen the variable bounds using the cumulative condition */
12344static
12346 SCIP* scip, /**< SCIP data structure */
12347 SCIP_CONS* cons, /**< constraint to propagate */
12348 int* nchgbds, /**< pointer to store the number of changed bounds */
12349 int* naddconss /**< pointer to store the number of added constraints */
12350 )
12351{
12352 SCIP_CONSDATA* consdata;
12353 SCIP_VAR** vars;
12354 int* durations;
12355 int* demands;
12356 int capacity;
12357 int nvars;
12358 int nconss;
12359 int i;
12360
12361 consdata = SCIPconsGetData(cons);
12362 assert(consdata != NULL);
12363
12364 /* check if the variable bounds got already strengthen by the cumulative constraint */
12365 if( consdata->varbounds )
12366 return SCIP_OKAY;
12367
12368 vars = consdata->vars;
12369 durations = consdata->durations;
12370 demands = consdata->demands;
12371 capacity = consdata->capacity;
12372 nvars = consdata->nvars;
12373
12374 nconss = 0;
12375
12376 for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12377 {
12378 SCIP_VAR** vbdvars;
12379 SCIP_VAR* var;
12380 SCIP_Real* vbdcoefs;
12381 SCIP_Real* vbdconsts;
12382 int nvbdvars;
12383 int b;
12384 int j;
12385
12386 var = consdata->vars[i];
12387 assert(var != NULL);
12388
12389 vbdvars = SCIPvarGetVlbVars(var);
12390 vbdcoefs = SCIPvarGetVlbCoefs(var);
12391 vbdconsts = SCIPvarGetVlbConstants(var);
12392 nvbdvars = SCIPvarGetNVlbs(var);
12393
12394 for( b = 0; b < nvbdvars; ++b )
12395 {
12396 if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12397 {
12398 if( boundedConvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12399 {
12400 for( j = 0; j < nvars; ++j )
12401 {
12402 if( vars[j] == vbdvars[b] )
12403 break;
12404 }
12405 if( j == nvars )
12406 continue;
12407
12408 if( demands[i] + demands[j] > capacity &&
12409 boundedConvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12410 {
12411 SCIP_Bool infeasible;
12412 char name[SCIP_MAXSTRLEN];
12413 int nlocalbdchgs;
12414
12415 SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12416
12417 /* construct constraint name */
12418 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12419
12420 SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12421 nconss++;
12422
12423 SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12424 assert(!infeasible);
12425
12426 (*nchgbds) += nlocalbdchgs;
12427 }
12428 }
12429 }
12430 }
12431 }
12432
12433 (*naddconss) += nconss;
12434
12435 consdata->varbounds = TRUE;
12436
12437 return SCIP_OKAY;
12438}
12439
12440/** helper function to enforce constraints */
12441static
12443 SCIP* scip, /**< SCIP data structure */
12444 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12445 SCIP_CONS** conss, /**< constraints to process */
12446 int nconss, /**< number of constraints */
12447 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12448 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12449 SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12450 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12451 )
12452{
12453 SCIP_CONSHDLRDATA* conshdlrdata;
12454
12455 assert(conshdlr != NULL);
12456 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12457 assert(nconss == 0 || conss != NULL);
12458 assert(result != NULL);
12459
12460 if( solinfeasible )
12461 {
12462 *result = SCIP_INFEASIBLE;
12463 return SCIP_OKAY;
12464 }
12465
12466 SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12467 sol == NULL ? "LP" : "relaxation");
12468
12469 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12470 assert(conshdlrdata != NULL);
12471
12472 (*result) = SCIP_FEASIBLE;
12473
12474 if( conshdlrdata->usebinvars )
12475 {
12476 SCIP_Bool separated;
12477 SCIP_Bool cutoff;
12478 int c;
12479
12480 separated = FALSE;
12481
12482 /* first check if a constraints is violated */
12483 for( c = 0; c < nusefulconss; ++c )
12484 {
12485 SCIP_CONS* cons;
12486 SCIP_Bool violated;
12487
12488 cons = conss[c];
12489 assert(cons != NULL);
12490
12491 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12492
12493 if( !violated )
12494 continue;
12495
12496 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12497 if ( cutoff )
12498 {
12499 *result = SCIP_CUTOFF;
12500 return SCIP_OKAY;
12501 }
12502 }
12503
12504 for( ; c < nconss && !separated; ++c )
12505 {
12506 SCIP_CONS* cons;
12507 SCIP_Bool violated;
12508
12509 cons = conss[c];
12510 assert(cons != NULL);
12511
12512 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12513
12514 if( !violated )
12515 continue;
12516
12517 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12518 if ( cutoff )
12519 {
12520 *result = SCIP_CUTOFF;
12521 return SCIP_OKAY;
12522 }
12523 }
12524
12525 if( separated )
12526 (*result) = SCIP_SEPARATED;
12527 }
12528 else
12529 {
12530 SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12531 }
12532
12533 return SCIP_OKAY;
12534}
12535
12536/**@} */
12537
12538
12539/**@name Callback methods of constraint handler
12540 *
12541 * @{
12542 */
12543
12544/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12545static
12546SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12547{ /*lint --e{715}*/
12548 assert(scip != NULL);
12549 assert(conshdlr != NULL);
12550 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
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 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12570
12571 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12572 assert(conshdlrdata != NULL);
12573
12574#ifdef SCIP_STATISTIC
12575 if( !conshdlrdata->iscopy )
12576 {
12577 /* statisitc output if SCIP_STATISTIC is defined */
12578 SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12579 conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12580 SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12581 conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12582 SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12583 conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12584 }
12585#endif
12586
12587 conshdlrdataFree(scip, &conshdlrdata);
12588
12589 SCIPconshdlrSetData(conshdlr, NULL);
12590
12591 return SCIP_OKAY;
12592}
12593
12594
12595/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12596static
12597SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12598{ /*lint --e{715}*/
12599 SCIP_CONSHDLRDATA* conshdlrdata;
12600 int c;
12601
12602 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12603 assert(conshdlrdata != NULL);
12604
12605 conshdlrdata->detectedredundant = FALSE;
12606
12607 for( c = 0; c < nconss; ++c )
12608 {
12609 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12610 * hmax)
12611 */
12612 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12613 }
12614
12615 return SCIP_OKAY;
12616}
12617
12618
12619/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12620#ifdef SCIP_STATISTIC
12621static
12622SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12623{ /*lint --e{715}*/
12624 SCIP_CONSHDLRDATA* conshdlrdata;
12625 int c;
12626
12627 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12628 assert(conshdlrdata != NULL);
12629
12630 for( c = 0; c < nconss; ++c )
12631 {
12632 SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12633
12634#ifdef SCIP_DISABLED_CODE
12636#endif
12637 }
12638
12639 if( !conshdlrdata->iscopy )
12640 {
12641 SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12642 SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12643 SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12644 SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12645 SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12646 SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12647 SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12648 SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12649 SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12650 }
12651
12652 return SCIP_OKAY;
12653}
12654#endif
12655
12656
12657/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12658static
12659SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12660{ /*lint --e{715}*/
12661 SCIP_CONSDATA* consdata;
12662 int c;
12663
12664 assert(conshdlr != NULL);
12665 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12666
12667 /* release the rows of all constraints */
12668 for( c = 0; c < nconss; ++c )
12669 {
12670 consdata = SCIPconsGetData(conss[c]);
12671 assert(consdata != NULL);
12672
12673 /* free rows */
12674 SCIP_CALL( consdataFreeRows(scip, &consdata) );
12675 }
12676
12677 return SCIP_OKAY;
12678}
12679
12680/** frees specific constraint data */
12681static
12682SCIP_DECL_CONSDELETE(consDeleteCumulative)
12683{ /*lint --e{715}*/
12684 assert(conshdlr != NULL);
12685 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12686 assert(consdata != NULL );
12687 assert(*consdata != NULL );
12688
12689 /* if constraint belongs to transformed problem space, drop bound change events on variables */
12690 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12691 {
12692 SCIP_CONSHDLRDATA* conshdlrdata;
12693
12694 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12695 assert(conshdlrdata != NULL);
12696
12697 SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12698 }
12699
12700 /* free cumulative constraint data */
12701 SCIP_CALL( consdataFree(scip, consdata) );
12702
12703 return SCIP_OKAY;
12704}
12705
12706/** transforms constraint data into data belonging to the transformed problem */
12707static
12708SCIP_DECL_CONSTRANS(consTransCumulative)
12709{ /*lint --e{715}*/
12710 SCIP_CONSHDLRDATA* conshdlrdata;
12711 SCIP_CONSDATA* sourcedata;
12712 SCIP_CONSDATA* targetdata;
12713
12714 assert(conshdlr != NULL);
12716 assert(sourcecons != NULL);
12717 assert(targetcons != NULL);
12718
12719 sourcedata = SCIPconsGetData(sourcecons);
12720 assert(sourcedata != NULL);
12721 assert(sourcedata->demandrows == NULL);
12722
12723 SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12724
12725 /* get event handler */
12726 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12727 assert(conshdlrdata != NULL);
12728 assert(conshdlrdata->eventhdlr != NULL);
12729
12730 /* create constraint data for target constraint */
12731 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12732 sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12733 sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12734
12735 /* create target constraint */
12736 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12737 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12738 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12739 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12740 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12741
12742 /* catch bound change events of variables */
12743 SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12744
12745 return SCIP_OKAY;
12746}
12747
12748/** LP initialization method of constraint handler */
12749static
12750SCIP_DECL_CONSINITLP(consInitlpCumulative)
12751{
12752 SCIP_CONSHDLRDATA* conshdlrdata;
12753 int c;
12754
12755 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12756 assert(conshdlr != NULL);
12757 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12758 assert(conshdlrdata != NULL);
12759
12760 *infeasible = FALSE;
12761
12762 SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12763
12764 if( conshdlrdata->usebinvars )
12765 {
12766 /* add rows to LP */
12767 for( c = 0; c < nconss && !(*infeasible); ++c )
12768 {
12769 assert(SCIPconsIsInitial(conss[c]));
12770 SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12771
12772 if( conshdlrdata->cutsasconss )
12773 {
12775 }
12776 }
12777 }
12778
12779 /**@todo if we want to use only the integer variables; only these will be in cuts
12780 * create some initial cuts, currently these are only separated */
12781
12782 return SCIP_OKAY;
12783}
12784
12785/** separation method of constraint handler for LP solutions */
12786static
12787SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12788{
12789 SCIP_CONSHDLRDATA* conshdlrdata;
12790 SCIP_Bool cutoff;
12791 SCIP_Bool separated;
12792 int c;
12793
12794 SCIPdebugMsg(scip, "consSepalpCumulative\n");
12795
12796 assert(conshdlr != NULL);
12797 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12798 assert(nconss == 0 || conss != NULL);
12799 assert(result != NULL);
12800 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12801 assert(conshdlrdata != NULL);
12802
12803 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12804
12805 cutoff = FALSE;
12806 separated = FALSE;
12807 (*result) = SCIP_DIDNOTRUN;
12808
12809 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12810 return SCIP_OKAY;
12811
12812 (*result) = SCIP_DIDNOTFIND;
12813
12814 if( conshdlrdata->usebinvars )
12815 {
12816 /* check all useful cumulative constraints for feasibility */
12817 for( c = 0; c < nusefulconss && !cutoff; ++c )
12818 {
12819 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12820 }
12821
12822 if( !cutoff && conshdlrdata->usecovercuts )
12823 {
12824 for( c = 0; c < nusefulconss; ++c )
12825 {
12826 SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12827 }
12828 }
12829 }
12830
12831 if( conshdlrdata->sepaold )
12832 {
12833 /* separate cuts containing only integer variables */
12834 for( c = 0; c < nusefulconss; ++c )
12835 {
12836 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12837 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12838 }
12839 }
12840
12841 if( cutoff )
12842 *result = SCIP_CUTOFF;
12843 else if( separated )
12844 *result = SCIP_SEPARATED;
12845
12846 return SCIP_OKAY;
12847}
12848
12849/** separation method of constraint handler for arbitrary primal solutions */
12850static
12851SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12852{ /*lint --e{715}*/
12853 SCIP_CONSHDLRDATA* conshdlrdata;
12854 SCIP_Bool cutoff;
12855 SCIP_Bool separated;
12856 int c;
12857
12858 assert(conshdlr != NULL);
12859 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12860 assert(nconss == 0 || conss != NULL);
12861 assert(result != NULL);
12862
12863 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12864 assert(conshdlrdata != NULL);
12865
12866 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12867 return SCIP_OKAY;
12868
12869 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12870
12871 cutoff = FALSE;
12872 separated = FALSE;
12873 (*result) = SCIP_DIDNOTFIND;
12874
12875 if( conshdlrdata->usebinvars )
12876 {
12877 /* check all useful cumulative constraints for feasibility */
12878 for( c = 0; c < nusefulconss && !cutoff; ++c )
12879 {
12880 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12881 }
12882
12883 if( !cutoff && conshdlrdata->usecovercuts )
12884 {
12885 for( c = 0; c < nusefulconss; ++c )
12886 {
12887 SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12888 }
12889 }
12890 }
12891 if( conshdlrdata->sepaold )
12892 {
12893 /* separate cuts containing only integer variables */
12894 for( c = 0; c < nusefulconss; ++c )
12895 {
12896 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12897 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12898 }
12899 }
12900
12901 if( cutoff )
12902 *result = SCIP_CUTOFF;
12903 else if( separated )
12904 *result = SCIP_SEPARATED;
12905
12906 return SCIP_OKAY;
12907}
12908
12909/** constraint enforcing method of constraint handler for LP solutions */
12910static
12911SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12912{ /*lint --e{715}*/
12913 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12914
12915 return SCIP_OKAY;
12916}
12917
12918/** constraint enforcing method of constraint handler for relaxation solutions */
12919static
12920SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
12921{ /*lint --e{715}*/
12922 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12923
12924 return SCIP_OKAY;
12925}
12926
12927/** constraint enforcing method of constraint handler for pseudo solutions */
12928static
12929SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12930{ /*lint --e{715}*/
12931 SCIP_CONSHDLRDATA* conshdlrdata;
12932
12933 SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
12934
12935 assert(conshdlr != NULL);
12936 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12937 assert(nconss == 0 || conss != NULL);
12938 assert(result != NULL);
12939
12940 if( objinfeasible )
12941 {
12942 *result = SCIP_DIDNOTRUN;
12943 return SCIP_OKAY;
12944 }
12945
12946 (*result) = SCIP_FEASIBLE;
12947
12948 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12949 assert(conshdlrdata != NULL);
12950
12951 SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
12952
12953 return SCIP_OKAY;
12954}
12955
12956/** feasibility check method of constraint handler for integral solutions */
12957static
12958SCIP_DECL_CONSCHECK(consCheckCumulative)
12959{ /*lint --e{715}*/
12960 int c;
12961
12962 assert(conshdlr != NULL);
12963 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12964 assert(nconss == 0 || conss != NULL);
12965 assert(result != NULL);
12966
12967 *result = SCIP_FEASIBLE;
12968
12969 SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
12970
12971 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
12972 {
12973 SCIP_Bool violated = FALSE;
12974
12975 SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
12976
12977 if( violated )
12978 *result = SCIP_INFEASIBLE;
12979 }
12980
12981 return SCIP_OKAY;
12982}
12983
12984/** domain propagation method of constraint handler */
12985static
12986SCIP_DECL_CONSPROP(consPropCumulative)
12987{ /*lint --e{715}*/
12988 SCIP_CONSHDLRDATA* conshdlrdata;
12989 SCIP_Bool cutoff;
12990 int nchgbds;
12991 int ndelconss;
12992 int c;
12993
12994 SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
12995
12996 assert(conshdlr != NULL);
12997 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12998 assert(nconss == 0 || conss != NULL);
12999 assert(result != NULL);
13000
13001 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13002 assert(conshdlrdata != NULL);
13003
13004 nchgbds = 0;
13005 ndelconss = 0;
13006 cutoff = FALSE;
13007 (*result) = SCIP_DIDNOTRUN;
13008
13009 /* propgate all useful constraints */
13010 for( c = 0; c < nusefulconss && !cutoff; ++c )
13011 {
13012 SCIP_CONS* cons;
13013
13014 cons = conss[c];
13015 assert(cons != NULL);
13016
13017 if( SCIPgetDepth(scip) == 0 )
13018 {
13020 &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13021
13022 if( cutoff )
13023 break;
13024
13025 if( SCIPconsIsDeleted(cons) )
13026 continue;
13027 }
13028
13029 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13030 }
13031
13032 if( !cutoff && nchgbds == 0 )
13033 {
13034 /* propgate all other constraints */
13035 for( c = nusefulconss; c < nconss && !cutoff; ++c )
13036 {
13037 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13038 }
13039 }
13040
13041 if( cutoff )
13042 {
13043 SCIPdebugMsg(scip, "detected infeasible\n");
13044 *result = SCIP_CUTOFF;
13045 }
13046 else if( nchgbds > 0 )
13047 {
13048 SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13049 *result = SCIP_REDUCEDDOM;
13050 }
13051 else
13052 *result = SCIP_DIDNOTFIND;
13053
13054 return SCIP_OKAY;
13055}
13056
13057/** presolving method of constraint handler */
13058static
13059SCIP_DECL_CONSPRESOL(consPresolCumulative)
13060{ /*lint --e{715}*/
13061 SCIP_CONSHDLRDATA* conshdlrdata;
13062 SCIP_CONS* cons;
13063 SCIP_Bool cutoff;
13064 SCIP_Bool unbounded;
13065 int oldnfixedvars;
13066 int oldnchgbds;
13067 int oldndelconss;
13068 int oldnaddconss;
13069 int oldnupgdconss;
13070 int oldnchgsides;
13071 int oldnchgcoefs;
13072 int c;
13073
13074 assert(conshdlr != NULL);
13075 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13076 assert(scip != NULL);
13077 assert(result != NULL);
13078
13079 SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13080
13081 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13082 assert(conshdlrdata != NULL);
13083
13084 *result = SCIP_DIDNOTRUN;
13085
13086 oldnfixedvars = *nfixedvars;
13087 oldnchgbds = *nchgbds;
13088 oldnchgsides = *nchgsides;
13089 oldnchgcoefs = *nchgcoefs;
13090 oldnupgdconss = *nupgdconss;
13091 oldndelconss = *ndelconss;
13092 oldnaddconss = *naddconss;
13093 cutoff = FALSE;
13094 unbounded = FALSE;
13095
13096 /* process constraints */
13097 for( c = 0; c < nconss && !cutoff; ++c )
13098 {
13099 cons = conss[c];
13100
13101 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13102 * hmax)
13103 */
13104 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13105
13106 if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13107 {
13108 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13109 nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13110
13111 if( cutoff || unbounded )
13112 break;
13113
13114 if( SCIPconsIsDeleted(cons) )
13115 continue;
13116 }
13117
13118 /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13119 if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13120 {
13121 SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13122 }
13123
13124 /* strengthen existing variable bounds using the cumulative condition */
13125 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13126 {
13127 SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13128 }
13129
13130 /* propagate cumulative constraint */
13131 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13132 assert(checkDemands(scip, cons) || cutoff);
13133 }
13134
13135 if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13136 {
13137 SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13138 }
13139
13140 /* only perform the detection of variable bounds and disjunctive constraint once */
13141 if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13142 && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13143 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13144 {
13145 /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13146 * propagation
13147 */
13148 SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13149 conshdlrdata->detectedredundant = TRUE;
13150 }
13151
13152 if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13153 {
13154 SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13155 }
13156
13157 SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13158 *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13159
13160 if( cutoff )
13161 *result = SCIP_CUTOFF;
13162 else if( unbounded )
13163 *result = SCIP_UNBOUNDED;
13164 else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13165 || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13166 *result = SCIP_SUCCESS;
13167 else
13168 *result = SCIP_DIDNOTFIND;
13169
13170 return SCIP_OKAY;
13171}
13172
13173/** propagation conflict resolving method of constraint handler */
13174static
13175SCIP_DECL_CONSRESPROP(consRespropCumulative)
13176{ /*lint --e{715}*/
13177 SCIP_CONSHDLRDATA* conshdlrdata;
13178 SCIP_CONSDATA* consdata;
13179
13180 assert(conshdlr != NULL);
13181 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13182 assert(scip != NULL);
13183 assert(result != NULL);
13184 assert(infervar != NULL);
13185 assert(bdchgidx != NULL);
13186
13187 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13188 assert(conshdlrdata != NULL);
13189
13190 /* process constraint */
13191 assert(cons != NULL);
13192
13193 consdata = SCIPconsGetData(cons);
13194 assert(consdata != NULL);
13195
13196 SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13197 SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13199
13200 SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13201 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13202 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13203
13204 return SCIP_OKAY;
13205}
13206
13207/** variable rounding lock method of constraint handler */
13208static
13209SCIP_DECL_CONSLOCK(consLockCumulative)
13210{ /*lint --e{715}*/
13211 SCIP_CONSDATA* consdata;
13212 SCIP_VAR** vars;
13213 int v;
13214
13215 SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13216
13217 assert(scip != NULL);
13218 assert(cons != NULL);
13219 assert(locktype == SCIP_LOCKTYPE_MODEL);
13220
13221 consdata = SCIPconsGetData(cons);
13222 assert(consdata != NULL);
13223
13224 vars = consdata->vars;
13225 assert(vars != NULL);
13226
13227 for( v = 0; v < consdata->nvars; ++v )
13228 {
13229 if( consdata->downlocks[v] && consdata->uplocks[v] )
13230 {
13231 /* the integer start variable should not get rounded in both direction */
13232 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13233 }
13234 else if( consdata->downlocks[v] )
13235 {
13236 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13237 }
13238 else if( consdata->uplocks[v] )
13239 {
13240 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13241 }
13242 }
13243
13244 return SCIP_OKAY;
13245}
13246
13247
13248/** constraint display method of constraint handler */
13249static
13250SCIP_DECL_CONSPRINT(consPrintCumulative)
13251{ /*lint --e{715}*/
13252 assert(scip != NULL);
13253 assert(conshdlr != NULL);
13254 assert(cons != NULL);
13255
13256 consdataPrint(scip, SCIPconsGetData(cons), file);
13257
13258 return SCIP_OKAY;
13259}
13260
13261/** constraint copying method of constraint handler */
13262static
13263SCIP_DECL_CONSCOPY(consCopyCumulative)
13264{ /*lint --e{715}*/
13265 SCIP_CONSDATA* sourceconsdata;
13266 SCIP_VAR** sourcevars;
13267 SCIP_VAR** vars;
13268 const char* consname;
13269
13270 int nvars;
13271 int v;
13272
13273 sourceconsdata = SCIPconsGetData(sourcecons);
13274 assert(sourceconsdata != NULL);
13275
13276 /* get variables of the source constraint */
13277 nvars = sourceconsdata->nvars;
13278 sourcevars = sourceconsdata->vars;
13279
13280 (*valid) = TRUE;
13281
13282 if( nvars == 0 )
13283 return SCIP_OKAY;
13284
13285 /* allocate buffer array */
13286 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13287
13288 for( v = 0; v < nvars && *valid; ++v )
13289 {
13290 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13291 assert(!(*valid) || vars[v] != NULL);
13292 }
13293
13294 /* only create the target constraint, if all variables could be copied */
13295 if( *valid )
13296 {
13297 if( name != NULL )
13298 consname = name;
13299 else
13300 consname = SCIPconsGetName(sourcecons);
13301
13302 /* create a copy of the cumulative constraint */
13303 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13304 sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13305 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13306
13307 /* adjust left side if the time axis if needed */
13308 if( sourceconsdata->hmin > 0 )
13309 {
13310 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13311 }
13312
13313 /* adjust right side if the time axis if needed */
13314 if( sourceconsdata->hmax < INT_MAX )
13315 {
13316 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13317 }
13318 }
13319
13320 /* free buffer array */
13321 SCIPfreeBufferArray(scip, &vars);
13322
13323 return SCIP_OKAY;
13324}
13325
13326
13327/** constraint parsing method of constraint handler */
13328static
13329SCIP_DECL_CONSPARSE(consParseCumulative)
13330{ /*lint --e{715}*/
13331 SCIP_VAR** vars;
13332 SCIP_VAR* var;
13333 SCIP_Real value;
13334 char strvalue[SCIP_MAXSTRLEN];
13335 char* endptr;
13336 int* demands;
13337 int* durations;
13338 int capacity;
13339 int duration;
13340 int demand;
13341 int hmin;
13342 int hmax;
13343 int varssize;
13344 int nvars;
13345
13346 SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13347
13348 *success = TRUE;
13349
13350 /* cutoff "cumulative" form the constraint string */
13351 SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13352 str = endptr;
13353
13354 varssize = 100;
13355 nvars = 0;
13356
13357 /* allocate buffer array for variables */
13358 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13359 SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13360 SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13361
13362 do
13363 {
13364 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13365
13366 if( var == NULL )
13367 {
13368 endptr = strchr(endptr, ')');
13369
13370 if( endptr == NULL )
13371 *success = FALSE;
13372 else
13373 str = endptr;
13374
13375 break;
13376 }
13377
13378 str = endptr;
13379 SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13380 duration = atoi(strvalue);
13381 str = endptr;
13382
13383 SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13384 demand = atoi(strvalue);
13385 str = endptr;
13386
13387 SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13388
13389 vars[nvars] = var;
13390 demands[nvars] = demand;
13391 durations[nvars] = duration;
13392 nvars++;
13393 }
13394 while( *str != ')' );
13395
13396 if( *success )
13397 {
13398 /* parse effective time window */
13399 SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13400 hmin = atoi(strvalue);
13401 str = endptr;
13402
13403 if( SCIPparseReal(scip, str, &value, &endptr) )
13404 {
13405 hmax = boundedConvertRealToInt(scip, value);
13406 str = endptr;
13407
13408 /* parse capacity */
13409 SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13410 str = endptr;
13411 if( SCIPparseReal(scip, str, &value, &endptr) )
13412 {
13413 capacity = (int)value;
13414
13415 /* create cumulative constraint */
13416 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13417 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13418
13419 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13420 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13421 }
13422 }
13423 }
13424
13425 /* free buffer arrays */
13426 SCIPfreeBufferArray(scip, &durations);
13427 SCIPfreeBufferArray(scip, &demands);
13428 SCIPfreeBufferArray(scip, &vars);
13429
13430 return SCIP_OKAY;
13431}
13432
13433
13434/** constraint method of constraint handler which returns the variables (if possible) */
13435static
13436SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13437{ /*lint --e{715}*/
13438 SCIP_CONSDATA* consdata;
13439
13440 consdata = SCIPconsGetData(cons);
13441 assert(consdata != NULL);
13442
13443 if( varssize < consdata->nvars )
13444 (*success) = FALSE;
13445 else
13446 {
13447 assert(vars != NULL);
13448
13449 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13450 (*success) = TRUE;
13451 }
13452
13453 return SCIP_OKAY;
13454}
13455
13456/** constraint method of constraint handler which returns the number of variables (if possible) */
13457static
13458SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13459{ /*lint --e{715}*/
13460 SCIP_CONSDATA* consdata;
13461
13462 consdata = SCIPconsGetData(cons);
13463 assert(consdata != NULL);
13464
13465 (*nvars) = consdata->nvars;
13466 (*success) = TRUE;
13467
13468 return SCIP_OKAY;
13469}
13470
13471/**@} */
13472
13473/**@name Callback methods of event handler
13474 *
13475 * @{
13476 */
13477
13478
13479/** execution method of event handler */
13480static
13481SCIP_DECL_EVENTEXEC(eventExecCumulative)
13482{ /*lint --e{715}*/
13483 SCIP_CONSDATA* consdata;
13484
13485 assert(scip != NULL);
13486 assert(eventhdlr != NULL);
13487 assert(eventdata != NULL);
13488 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13489 assert(event != NULL);
13490
13491 consdata = (SCIP_CONSDATA*)eventdata;
13492 assert(consdata != NULL);
13493
13494 /* mark the constraint to be not propagated */
13495 consdata->propagated = FALSE;
13496
13497 return SCIP_OKAY;
13498}
13499
13500/**@} */
13501
13502/*
13503 * constraint specific interface methods
13504 */
13505
13506/** creates the handler for cumulative constraints and includes it in SCIP */
13508 SCIP* scip /**< SCIP data structure */
13509 )
13510{
13511 SCIP_CONSHDLRDATA* conshdlrdata;
13512 SCIP_CONSHDLR* conshdlr;
13513 SCIP_EVENTHDLR* eventhdlr;
13514
13515 /* create event handler for bound change events */
13516 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13517
13518 /* create cumulative constraint handler data */
13519 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13520
13521 /* include constraint handler */
13524 consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13525 conshdlrdata) );
13526
13527 assert(conshdlr != NULL);
13528
13529 /* set non-fundamental callbacks via specific setter functions */
13530 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13531 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13532#ifdef SCIP_STATISTIC
13533 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13534#endif
13535 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13536 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13537 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13538 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13539 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13540 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13541 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13542 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13544 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13547 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13548 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13550 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13551 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13552
13553 /* add cumulative constraint handler parameters */
13555 "constraints/" CONSHDLR_NAME "/maxtime", "maximum range for time horizon",
13556 &conshdlrdata->maxtime, TRUE, DEFAULT_MAXTIME, 0, INT_MAX, NULL, NULL) );
13558 "constraints/" CONSHDLR_NAME "/ttinfer",
13559 "should time-table (core-times) propagator be used to infer bounds?",
13560 &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13562 "constraints/" CONSHDLR_NAME "/efcheck",
13563 "should edge-finding be used to detect an overload?",
13564 &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13566 "constraints/" CONSHDLR_NAME "/efinfer",
13567 "should edge-finding be used to infer bounds?",
13568 &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13570 "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13571 &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13573 "constraints/" CONSHDLR_NAME "/ttefcheck",
13574 "should time-table edge-finding be used to detect an overload?",
13575 &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13577 "constraints/" CONSHDLR_NAME "/ttefinfer",
13578 "should time-table edge-finding be used to infer bounds?",
13579 &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13580
13582 "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13583 &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13585 "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13586 &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13588 "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13589 &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13591 "constraints/" CONSHDLR_NAME "/cutsasconss",
13592 "should the cumulative constraint create cuts as knapsack constraints?",
13593 &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13595 "constraints/" CONSHDLR_NAME "/sepaold",
13596 "shall old sepa algo be applied?",
13597 &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13598
13600 "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13601 &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13602
13603 /* presolving parameters */
13605 "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13606 &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13608 "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13609 &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13611 "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13612 &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13614 "constraints/" CONSHDLR_NAME "/presolpairwise",
13615 "should pairwise constraint comparison be performed in presolving?",
13616 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13618 "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13619 &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13620
13622 "constraints/" CONSHDLR_NAME "/maxnodes",
13623 "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13624 &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13626 "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13627 &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13629 "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13630 &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13631
13632 /* conflict analysis parameters */
13634 "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13635 &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13636
13637 return SCIP_OKAY;
13638}
13639
13640/** creates and captures a cumulative constraint */
13642 SCIP* scip, /**< SCIP data structure */
13643 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13644 const char* name, /**< name of constraint */
13645 int nvars, /**< number of variables (jobs) */
13646 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13647 int* durations, /**< array containing corresponding durations */
13648 int* demands, /**< array containing corresponding demands */
13649 int capacity, /**< available cumulative capacity */
13650 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13651 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13652 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13653 * Usually set to TRUE. */
13654 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13655 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13656 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13657 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13658 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13659 * Usually set to TRUE. */
13660 SCIP_Bool local, /**< is constraint only valid locally?
13661 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13662 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13663 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13664 * adds coefficients to this constraint. */
13665 SCIP_Bool dynamic, /**< is constraint subject to aging?
13666 * Usually set to FALSE. Set to TRUE for own cuts which
13667 * are seperated as constraints. */
13668 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13669 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13670 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13671 * if it may be moved to a more global node?
13672 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13673 )
13674{
13675 int i;
13676 SCIP_CONSHDLR* conshdlr;
13677 SCIP_CONSDATA* consdata;
13678
13679 assert(scip != NULL);
13680
13681 /* find the cumulative constraint handler */
13682 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13683 if( conshdlr == NULL )
13684 {
13685 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13686 return SCIP_PLUGINNOTFOUND;
13687 }
13688
13689 for( i = 0; i < nvars; ++i )
13690 {
13691 if( INT_MAX - durations[i] < boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(vars[i])) )
13692 {
13693 SCIPerrorMessage("detected potential integer overflow for variable <%s> in constraint <%s>: "
13694 "decrease upper bound of variable or time horizon constraints/" CONSHDLR_NAME "/maxtime\n",
13695 name, SCIPvarGetName(vars[i]));
13696 return SCIP_INVALIDDATA;
13697 }
13698 }
13699 SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13700
13701 /* create constraint data */
13702 SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13703
13704 /* create constraint */
13705 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13706 initial, separate, enforce, check, propagate,
13707 local, modifiable, dynamic, removable, stickingatnode) );
13708
13710 {
13711 SCIP_CONSHDLRDATA* conshdlrdata;
13712
13713 /* get event handler */
13714 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13715 assert(conshdlrdata != NULL);
13716 assert(conshdlrdata->eventhdlr != NULL);
13717
13718 /* catch bound change events of variables */
13719 SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13720 }
13721
13722 return SCIP_OKAY;
13723}
13724
13725/** creates and captures a cumulative constraint
13726 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13727 * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13728 *
13729 * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13730 *
13731 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13732 */
13734 SCIP* scip, /**< SCIP data structure */
13735 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13736 const char* name, /**< name of constraint */
13737 int nvars, /**< number of variables (jobs) */
13738 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13739 int* durations, /**< array containing corresponding durations */
13740 int* demands, /**< array containing corresponding demands */
13741 int capacity /**< available cumulative capacity */
13742 )
13743{
13744 assert(scip != NULL);
13745
13746 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13748
13749 return SCIP_OKAY;
13750}
13751
13752/** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13754 SCIP* scip, /**< SCIP data structure */
13755 SCIP_CONS* cons, /**< constraint data */
13756 int hmin /**< left bound of time axis to be considered */
13757 )
13758{
13759 SCIP_CONSDATA* consdata;
13760 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13761 {
13762 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13763 return SCIP_INVALIDCALL;
13764 }
13765
13766 consdata = SCIPconsGetData(cons);
13767 assert(consdata != NULL);
13768
13769 if( hmin < 0 || hmin > consdata->hmax )
13770 {
13771 SCIPerrorMessage("invalid value of hmin for cumulative constraint <%s>\n",
13772 SCIPconsGetName(cons));
13773 return SCIP_INVALIDCALL;
13774 }
13775
13776 consdata->hmin = hmin;
13777
13778 return SCIP_OKAY;
13779}
13780
13781/** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13783 SCIP* scip, /**< SCIP data structure */
13784 SCIP_CONS* cons /**< constraint */
13785 )
13786{
13787 SCIP_CONSDATA* consdata;
13788 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13789 {
13790 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13791 SCIPABORT();
13792 return 0; /*lint !e527*/
13793 }
13794
13795 consdata = SCIPconsGetData(cons);
13796 assert(consdata != NULL);
13797
13798 return consdata->hmin;
13799}
13800
13801/** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13803 SCIP* scip, /**< SCIP data structure */
13804 SCIP_CONS* cons, /**< constraint data */
13805 int hmax /**< right bound of time axis to be considered */
13806 )
13807{
13808 SCIP_CONSDATA* consdata;
13809 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13810 {
13811 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13812 SCIPABORT();
13813 return SCIP_INVALIDCALL; /*lint !e527*/
13814 }
13815
13816 consdata = SCIPconsGetData(cons);
13817 assert(consdata != NULL);
13818
13819 if( hmax < consdata->hmin )
13820 {
13821 SCIPerrorMessage("invalid value of hmax for cumulative constraint <%s>\n",
13822 SCIPconsGetName(cons));
13823 return SCIP_INVALIDCALL;
13824 }
13825
13826 consdata->hmax = hmax;
13827
13828 return SCIP_OKAY;
13829}
13830
13831/** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13833 SCIP* scip, /**< SCIP data structure */
13834 SCIP_CONS* cons /**< constraint */
13835 )
13836{
13837 SCIP_CONSDATA* consdata;
13838 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13839 {
13840 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13841 SCIPABORT();
13842 return 0; /*lint !e527*/
13843 }
13844
13845 consdata = SCIPconsGetData(cons);
13846 assert(consdata != NULL);
13847
13848 return consdata->hmax;
13849}
13850
13851/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13853 SCIP* scip, /**< SCIP data structure */
13854 SCIP_CONS* cons /**< constraint data */
13855 )
13856{
13857 SCIP_CONSDATA* consdata;
13858
13859 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13860 {
13861 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13862 SCIPABORT();
13863 return NULL; /*lint !e527*/
13864 }
13865
13866 consdata = SCIPconsGetData(cons);
13867 assert(consdata != NULL);
13868
13869 return consdata->vars;
13870}
13871
13872/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13874 SCIP* scip, /**< SCIP data structure */
13875 SCIP_CONS* cons /**< constraint data */
13876 )
13877{
13878 SCIP_CONSDATA* consdata;
13879
13880 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13881 {
13882 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13883 SCIPABORT();
13884 return -1; /*lint !e527*/
13885 }
13886
13887 consdata = SCIPconsGetData(cons);
13888 assert(consdata != NULL);
13889
13890 return consdata->nvars;
13891}
13892
13893/** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13895 SCIP* scip, /**< SCIP data structure */
13896 SCIP_CONS* cons /**< constraint data */
13897 )
13898{
13899 SCIP_CONSDATA* consdata;
13900
13901 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13902 {
13903 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13904 SCIPABORT();
13905 return -1; /*lint !e527*/
13906 }
13907
13908 consdata = SCIPconsGetData(cons);
13909 assert(consdata != NULL);
13910
13911 return consdata->capacity;
13912}
13913
13914/** returns the durations 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
13922 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13923 {
13924 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13925 SCIPABORT();
13926 return NULL; /*lint !e527*/
13927 }
13928
13929 consdata = SCIPconsGetData(cons);
13930 assert(consdata != NULL);
13931
13932 return consdata->durations;
13933}
13934
13935/** returns the demands of the cumulative constraint */ /*lint -e{715}*/
13937 SCIP* scip, /**< SCIP data structure */
13938 SCIP_CONS* cons /**< constraint data */
13939 )
13940{
13941 SCIP_CONSDATA* consdata;
13942
13943 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13944 {
13945 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13946 SCIPABORT();
13947 return NULL; /*lint !e527*/
13948 }
13949
13950 consdata = SCIPconsGetData(cons);
13951 assert(consdata != NULL);
13952
13953 return consdata->demands;
13954}
13955
13956/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
13957 * given solution is satisfied
13958 */
13960 SCIP* scip, /**< SCIP data structure */
13961 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
13962 int nvars, /**< number of variables (jobs) */
13963 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13964 int* durations, /**< array containing corresponding durations */
13965 int* demands, /**< array containing corresponding demands */
13966 int capacity, /**< available cumulative capacity */
13967 int hmin, /**< left bound of time axis to be considered (including hmin) */
13968 int hmax, /**< right bound of time axis to be considered (not including hmax) */
13969 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
13970 SCIP_CONS* cons, /**< constraint which is checked */
13971 SCIP_Bool printreason /**< should the reason for the violation be printed? */
13972 )
13973{
13974 assert(scip != NULL);
13975 assert(violated != NULL);
13976
13977 SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
13978 violated, cons, printreason) );
13979
13980 return SCIP_OKAY;
13981}
13982
13983/** normalize cumulative condition */ /*lint -e{715}*/
13985 SCIP* scip, /**< SCIP data structure */
13986 int nvars, /**< number of start time variables (activities) */
13987 SCIP_VAR** vars, /**< array of start time variables */
13988 int* durations, /**< array of durations */
13989 int* demands, /**< array of demands */
13990 int* capacity, /**< pointer to store the changed cumulative capacity */
13991 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
13992 int* nchgsides /**< pointer to count number of side changes */
13993 )
13994{ /*lint --e{715}*/
13995 normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
13996
13997 return SCIP_OKAY;
13998}
13999
14000/** searches for a time point within the cumulative condition were the cumulative condition can be split */
14002 SCIP* scip, /**< SCIP data structure */
14003 int nvars, /**< number of variables (jobs) */
14004 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14005 int* durations, /**< array containing corresponding durations */
14006 int* demands, /**< array containing corresponding demands */
14007 int capacity, /**< available cumulative capacity */
14008 int* hmin, /**< pointer to store the left bound of the effective horizon */
14009 int* hmax, /**< pointer to store the right bound of the effective horizon */
14010 int* split /**< point were the cumulative condition can be split */
14011 )
14012{
14013 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14014 hmin, hmax, split) );
14015
14016 return SCIP_OKAY;
14017}
14018
14019/** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14021 SCIP* scip, /**< SCIP data structure */
14022 int nvars, /**< number of start time variables (activities) */
14023 SCIP_VAR** vars, /**< array of start time variables */
14024 int* durations, /**< array of durations */
14025 int hmin, /**< left bound of time axis to be considered */
14026 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14027 SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14028 SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14029 SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14030 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14031 int* nfixedvars, /**< pointer to store the number of fixed variables */
14032 int* nchgsides, /**< pointer to store the number of changed sides */
14033 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14034 )
14035{
14036 if( nvars <= 1 )
14037 return SCIP_OKAY;
14038
14039 /* presolve constraint form the earlier start time point of view */
14040 SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14041 irrelevants, nfixedvars, nchgsides, cutoff) );
14042
14043 /* presolve constraint form the latest completion time point of view */
14044 SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14045 irrelevants, nfixedvars, nchgsides, cutoff) );
14046
14047 return SCIP_OKAY;
14048}
14049
14050/** propagate the given cumulative condition */
14052 SCIP* scip, /**< SCIP data structure */
14053 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14054 int nvars, /**< number of variables (jobs) */
14055 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14056 int* durations, /**< array containing corresponding durations */
14057 int* demands, /**< array containing corresponding demands */
14058 int capacity, /**< available cumulative capacity */
14059 int hmin, /**< left bound of time axis to be considered (including hmin) */
14060 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14061 SCIP_CONS* cons, /**< constraint which gets propagated */
14062 int* nchgbds, /**< pointer to store the number of variable bound changes */
14063 SCIP_Bool* initialized, /**< was conflict analysis initialized */
14064 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14065 SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14066 )
14067{
14068 SCIP_CONSHDLR* conshdlr;
14069 SCIP_CONSHDLRDATA* conshdlrdata;
14070 SCIP_Bool redundant;
14071
14072 assert(scip != NULL);
14073 assert(cons != NULL);
14074 assert(initialized != NULL);
14075 assert(*initialized == FALSE);
14076 assert(cutoff != NULL);
14077 assert(*cutoff == FALSE);
14078
14079 /* find the cumulative constraint handler */
14080 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14081 if( conshdlr == NULL )
14082 {
14083 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14084 return SCIP_PLUGINNOTFOUND;
14085 }
14086
14087 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14088 assert(conshdlrdata != NULL);
14089
14090 redundant = FALSE;
14091
14092 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14093 nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14094 nchgbds, &redundant, initialized, explanation, cutoff) );
14095
14096 return SCIP_OKAY;
14097}
14098
14099/** resolve propagation w.r.t. the cumulative condition */
14101 SCIP* scip, /**< SCIP data structure */
14102 int nvars, /**< number of start time variables (activities) */
14103 SCIP_VAR** vars, /**< array of start time variables */
14104 int* durations, /**< array of durations */
14105 int* demands, /**< array of demands */
14106 int capacity, /**< cumulative capacity */
14107 int hmin, /**< left bound of time axis to be considered (including hmin) */
14108 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14109 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14110 int inferinfo, /**< the user information */
14111 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14112 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14113 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14114 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14115 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14116 )
14117{
14118 SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14119 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14120
14121 return SCIP_OKAY;
14122}
14123
14124/** this method visualizes the cumulative structure in GML format */
14126 SCIP* scip, /**< SCIP data structure */
14127 SCIP_CONS* cons /**< cumulative constraint */
14128 )
14129{
14130 SCIP_CONSDATA* consdata;
14131 SCIP_HASHTABLE* vars;
14132 FILE* file;
14133 SCIP_VAR* var;
14134 char filename[SCIP_MAXSTRLEN];
14135 int nvars;
14136 int v;
14137
14138 SCIP_RETCODE retcode = SCIP_OKAY;
14139
14140 /* open file */
14141 (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14142 file = fopen(filename, "w");
14143
14144 /* check if the file was open */
14145 if( file == NULL )
14146 {
14147 SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14148 SCIPprintSysError(filename);
14149 return SCIP_FILECREATEERROR;
14150 }
14151
14152 consdata = SCIPconsGetData(cons);
14153 assert(consdata != NULL);
14154
14155 nvars = consdata->nvars;
14156
14157 SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14158 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14159
14160 /* create opening of the GML format */
14162
14163 for( v = 0; v < nvars; ++v )
14164 {
14165 char color[SCIP_MAXSTRLEN];
14166
14167 var = consdata->vars[v];
14168 assert(var != NULL);
14169
14170 SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14171
14172 if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14173 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14174 else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14175 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14176 else
14177 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14178
14179 SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14180 }
14181
14182 for( v = 0; v < nvars; ++v )
14183 {
14184 SCIP_VAR** vbdvars;
14185 int nvbdvars;
14186 int b;
14187
14188 var = consdata->vars[v];
14189 assert(var != NULL);
14190
14191 vbdvars = SCIPvarGetVlbVars(var);
14192 nvbdvars = SCIPvarGetNVlbs(var);
14193
14194 for( b = 0; b < nvbdvars; ++b )
14195 {
14196 if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14197 {
14198 SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14199 }
14200 }
14201
14202#ifdef SCIP_MORE_OUTPUT
14203 /* define to also output variable bounds */
14204 vbdvars = SCIPvarGetVubVars(var);
14205 nvbdvars = SCIPvarGetNVubs(var);
14206
14207 for( b = 0; b < nvbdvars; ++b )
14208 {
14209 if( SCIPhashtableExists(vars, vbdvars[b]) )
14210 {
14211 SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14212 }
14213 }
14214#endif
14215 }
14216
14217 /* create closing of the GML format */
14218 SCIPgmlWriteClosing(file);
14219TERMINATE:
14220 /* close file */
14221 fclose(file);
14222
14223 SCIPhashtableFree(&vars);
14224
14225 return retcode;
14226}
14227
14228/** sets method to solve an individual cumulative condition */
14230 SCIP* scip, /**< SCIP data structure */
14231 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14232 )
14233{
14234 SCIP_CONSHDLR* conshdlr;
14235 SCIP_CONSHDLRDATA* conshdlrdata;
14236
14237 /* find the cumulative constraint handler */
14238 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14239 if( conshdlr == NULL )
14240 {
14241 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14242 return SCIP_PLUGINNOTFOUND;
14243 }
14244
14245 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14246 assert(conshdlrdata != NULL);
14247
14248 conshdlrdata->solveCumulative = solveCumulative;
14249
14250 return SCIP_OKAY;
14251}
14252
14253/** solves given cumulative condition as independent sub problem
14254 *
14255 * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14256 * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14257 * solver was interrupted.
14258 */
14260 SCIP* scip, /**< SCIP data structure */
14261 int njobs, /**< number of jobs (activities) */
14262 SCIP_Real* ests, /**< array with the earlier start time for each job */
14263 SCIP_Real* lsts, /**< array with the latest start time for each job */
14264 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14265 int* durations, /**< array of durations */
14266 int* demands, /**< array of demands */
14267 int capacity, /**< cumulative capacity */
14268 int hmin, /**< left bound of time axis to be considered (including hmin) */
14269 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14270 SCIP_Real timelimit, /**< time limit for solving in seconds */
14271 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14272 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14273 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14274 SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14275 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14276 SCIP_Bool* error /**< pointer to store if an error occurred */
14277 )
14278{
14279 SCIP_CONSHDLR* conshdlr;
14280 SCIP_CONSHDLRDATA* conshdlrdata;
14281
14282 (*solved) = TRUE;
14283 (*infeasible) = FALSE;
14284 (*unbounded) = FALSE;
14285 (*error) = FALSE;
14286
14287 if( njobs == 0 )
14288 return SCIP_OKAY;
14289
14290 /* find the cumulative constraint handler */
14291 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14292 if( conshdlr == NULL )
14293 {
14294 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14295 (*error) = TRUE;
14296 return SCIP_PLUGINNOTFOUND;
14297 }
14298
14299 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14300 assert(conshdlrdata != NULL);
14301
14302 /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14303 if( timelimit > 0.0 && memorylimit > 10 )
14304 {
14305 SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14306 hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14307 }
14308
14309 return SCIP_OKAY;
14310}
14311
14312/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14313 * completion time
14314 */
14316 SCIP* scip, /**< SCIP data structure */
14317 SCIP_PROFILE* profile, /**< resource profile */
14318 int nvars, /**< number of variables (jobs) */
14319 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14320 int* durations, /**< array containing corresponding durations */
14321 int* demands /**< array containing corresponding demands */
14322 )
14323{
14324 SCIP_VAR* var;
14325 SCIP_HASHMAP* addedvars;
14326 int* copydemands;
14327 int* perm;
14328 int duration;
14329 int impliedest;
14330 int est;
14331 int impliedlct;
14332 int lct;
14333 int v;
14334
14335 /* create hash map for variables which are added, mapping to their duration */
14336 SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14337
14338 SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14339 SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14340
14341 /* sort variables w.r.t. job demands */
14342 for( v = 0; v < nvars; ++v )
14343 {
14344 copydemands[v] = demands[v];
14345 perm[v] = v;
14346 }
14347 SCIPsortDownIntInt(copydemands, perm, nvars);
14348
14349 /* add each job with its earliest start and latest completion time into the resource profile */
14350 for( v = 0; v < nvars; ++v )
14351 {
14352 int idx;
14353
14354 idx = perm[v];
14355 assert(idx >= 0 && idx < nvars);
14356
14357 var = vars[idx];
14358 assert(var != NULL);
14359
14360 duration = durations[idx];
14361 assert(duration > 0);
14362
14364 SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14365
14366 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14367 SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14368
14369 if( impliedest < impliedlct )
14370 {
14371 SCIP_Bool infeasible;
14372 int pos;
14373
14374 SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14375 assert(!infeasible);
14376 assert(pos == -1);
14377 }
14378
14379 if( est == impliedest && lct == impliedlct )
14380 {
14381 SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14382 }
14383 }
14384
14385 SCIPfreeBufferArray(scip, &copydemands);
14386 SCIPfreeBufferArray(scip, &perm);
14387
14388 SCIPhashmapFree(&addedvars);
14389
14390 return SCIP_OKAY;
14391}
14392
14393/** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14395 SCIP* scip, /**< SCIP data structure */
14396 SCIP_PROFILE* profile, /**< worst case resource profile */
14397 int capacity /**< capacity to check */
14398 )
14399{
14400 int* timepoints;
14401 int* loads;
14402 int ntimepoints;
14403 int t;
14404
14405 ntimepoints = SCIPprofileGetNTimepoints(profile);
14406 timepoints = SCIPprofileGetTimepoints(profile);
14407 loads = SCIPprofileGetLoads(profile);
14408
14409 /* find first time point which potentially violates the capacity restriction */
14410 for( t = 0; t < ntimepoints - 1; ++t )
14411 {
14412 /* check if the time point exceed w.r.t. worst case profile the capacity */
14413 if( loads[t] > capacity )
14414 {
14415 assert(t == 0 || loads[t-1] <= capacity);
14416 return timepoints[t];
14417 }
14418 }
14419
14420 return INT_MAX;
14421}
14422
14423/** 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}*/
14425 SCIP* scip, /**< SCIP data structure */
14426 SCIP_PROFILE* profile, /**< worst case profile */
14427 int capacity /**< capacity to check */
14428 )
14429{
14430 int* timepoints;
14431 int* loads;
14432 int ntimepoints;
14433 int t;
14434
14435 ntimepoints = SCIPprofileGetNTimepoints(profile);
14436 timepoints = SCIPprofileGetTimepoints(profile);
14437 loads = SCIPprofileGetLoads(profile);
14438
14439 /* find last time point which potentially violates the capacity restriction */
14440 for( t = ntimepoints - 1; t >= 0; --t )
14441 {
14442 /* check if at time point t the worst case resource profile exceeds the capacity */
14443 if( loads[t] > capacity )
14444 {
14445 assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14446 return timepoints[t+1];
14447 }
14448 }
14449
14450 return INT_MIN;
14451}
static long bound
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
SCIP_VAR ** b
Definition: circlepacking.c:65
SCIP_Real * r
Definition: circlepacking.c:59
enum Proprule PROPRULE
Definition: cons_and.c:173
Proprule
Definition: cons_and.c:166
static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
enum Proprule PROPRULE
static SCIP_DECL_CONSPROP(consPropCumulative)
static int inferInfoGetData1(INFERINFO inferinfo)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define DEFAULT_USEBDWIDENING
#define CONSHDLR_NEEDSCONS
#define DEFAULT_SEPAOLD
#define CONSHDLR_SEPAFREQ
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)
static SCIP_DECL_CONSINITPRE(consInitpreCumulative)
#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)
#define CONSHDLR_CHECKPRIORITY
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
#define CONSHDLR_DESC
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_DECL_EVENTEXEC(eventExecCumulative)
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_DECL_CONSCOPY(consCopyCumulative)
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
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)
#define CONSHDLR_PROP_TIMING
static SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
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)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE tightenUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int lst, int lct, int begin, int end, SCIP_Longint energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSCHECK(consCheckCumulative)
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)
#define DEFAULT_PRESOLPAIRWISE
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_DECL_CONSENFORELAX(consEnforelaxCumulative)
static SCIP_RETCODE presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
#define DEFAULT_EFINFER
#define CONSHDLR_SEPAPRIORITY
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_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
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)
static SCIP_DECL_SORTPTRCOMP(compNodeEst)
#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 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
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_DECL_CONSRESPROP(consRespropCumulative)
static SCIP_RETCODE removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
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)
static SCIP_DECL_SORTINDCOMP(compNodedataLct)
struct SCIP_NodeData SCIP_NODEDATA
#define DEFAULT_CUTSASCONSS
#define DEFAULT_DUALPRESOLVE
static SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
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
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
@ 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_DECL_CONSLOCK(consLockCumulative)
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 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
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_DECL_CONSFREE(consFreeCumulative)
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_DECL_CONSPRINT(consPrintCumulative)
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)
#define CONSHDLR_PROPFREQ
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)
#define CONSHDLR_PRESOLTIMING
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 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
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 SCIP_DECL_CONSDELETE(consDeleteCumulative)
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 CONSHDLR_EAGERFREQ
#define DEFAULT_USEBINVARS
#define EVENTHDLR_DESC
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)
#define CONSHDLR_ENFOPRIORITY
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 SCIP_DECL_CONSPARSE(consParseCumulative)
static SCIP_DECL_CONSPRESOL(consPresolCumulative)
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
#define CONSHDLR_DELAYSEPA
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 TCLIQUE_NEWSOL(tcliqueNewsolClique)
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 SCIP_DECL_CONSINITLP(consInitlpCumulative)
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
#define CONSHDLR_NAME
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
static int inferInfoToInt(INFERINFO inferinfo)
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define EVENTHDLR_NAME
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_DECL_CONSTRANS(consTransCumulative)
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)
#define CONSHDLR_DELAYPROP
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:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define SCIP_UNKNOWN
Definition: def.h:179
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:376
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define MIN3(x, y, z)
Definition: def.h:232
#define SCIPABORT()
Definition: def.h:327
#define SCIP_LONGINT_MAX
Definition: def.h:142
#define SCIP_CALL(x)
Definition: def.h:355
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:397
#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 SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:9442
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)
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_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)
Definition: cons_setppc.c:9573
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)
Definition: scip_general.c:647
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:402
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:370
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:562
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
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,...)
Definition: scip_message.c:208
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
#define SCIPdebugMsg
Definition: scip_message.h:78
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)
Definition: scip_branch.c:673
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1099
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)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4346
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
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 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 SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4316
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4336
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8419
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8648
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8409
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8558
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:8588
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8518
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8698
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:8578
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8450
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:8608
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8628
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8389
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1812
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8638
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:8668
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8568
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1138
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8658
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)
Definition: scip_probing.c:98
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:2981
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:453
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3603
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2635
int SCIPgetNRuns(SCIP *scip)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
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:23514
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:24482
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:24504
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
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:23386
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4386
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:23430
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:23900
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:23453
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:24142
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:23652
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:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1887
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:24514
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:24524
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:23524
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:24494
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:24120
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:17274
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:24556
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:24536
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:24546
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4328
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
#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)
Definition: pub_message.h:102
#define SCIPstatisticPrintf
Definition: pub_message.h:126
#define SCIPdebugMessage
Definition: pub_message.h:96
#define SCIPstatistic(x)
Definition: pub_message.h:120
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.
Definition: sepa_flower.c:1221
tclique user interface
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
@ SCIP_CONFTYPE_PROPAGATION
Definition: type_conflict.h:62
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:180
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:179
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:125
@ 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
@ SCIP_PARAMEMPHASIS_CPSOLVER
Definition: type_paramset.h:72
@ 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
Definition: type_retcode.h:48
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ 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
@ 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
@ 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