Scippy

SCIP

Solving Constraint Integer Programs

cons_cumulative.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_cumulative.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for cumulative constraints
28 * @author Timo Berthold
29 * @author Stefan Heinz
30 * @author Jens Schulz
31 *
32 * Given:
33 * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
34 * their demands \f$d_j\f$.
35 * - an integer resource capacity \f$C\f$
36 *
37 * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
38 *
39 * Separation:
40 * - can be done using binary start time model, see Pritskers, Watters and Wolfe
41 * - or by just separating relatively weak cuts on the integer start time variables
42 *
43 * Propagation:
44 * - time tabling, Klein & Scholl (1999)
45 * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
46 * (2009)
47 * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
48 *
49 */
50
51/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
52
53#include <assert.h>
54#include <string.h>
55
56#include "tclique/tclique.h"
58#include "scip/cons_linking.h"
59#include "scip/cons_knapsack.h"
60#include "scip/scipdefplugins.h"
61
62/**@name Constraint handler properties
63 *
64 * @{
65 */
66
67/* constraint handler properties */
68#define CONSHDLR_NAME "cumulative"
69#define CONSHDLR_DESC "cumulative constraint handler"
70#define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
71#define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
72#define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
73#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
74#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
75#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
76 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
77#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
78#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
79#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
80#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
81
82#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
83#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
84
85/**@} */
86
87/**@name Default parameter values
88 *
89 * @{
90 */
91
92/* default parameter values */
93
94/* separation */
95#define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
96#define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
97#define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
98#define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
99#define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
100
101/* propagation */
102#define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
103#define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
104#define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
105#define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
106#define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
107#define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
108
109/* presolving */
110#define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
111#define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
112#define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
113#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
114#define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
115#define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
116#define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
117#define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
118
119/* enforcement */
120#define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
121
122/* conflict analysis */
123#define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
124
125/**@} */
126
127/**@name Event handler properties
128 *
129 * @{
130 */
131
132#define EVENTHDLR_NAME "cumulative"
133#define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
134
135/**@} */
136
137/*
138 * Data structures
139 */
140
141/** constraint data for cumulative constraints */
142struct SCIP_ConsData
143{
144 SCIP_VAR** vars; /**< array of variable representing the start time of each job */
145 SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
146 SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
147 SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
148 SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
149 SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
150 SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
151 int* demands; /**< array containing corresponding demands */
152 int* durations; /**< array containing corresponding durations */
153 SCIP_Real resstrength1; /**< stores the resource strength 1*/
154 SCIP_Real resstrength2; /**< stores the resource strength 2 */
155 SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
156 SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
157 SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
158 SCIP_Real estimatedstrength;
159 int nvars; /**< number of variables */
160 int varssize; /**< size of the arrays */
161 int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
162 int demandrowssize; /**< size of array rows of demand rows */
163 int nscoverrows; /**< number of rows of small cover cuts */
164 int scoverrowssize; /**< size of array of small cover cuts */
165 int nbcoverrows; /**< number of rows of big cover cuts */
166 int bcoverrowssize; /**< size of array of big cover cuts */
167 int capacity; /**< available cumulative capacity */
168
169 int hmin; /**< left bound of time axis to be considered (including hmin) */
170 int hmax; /**< right bound of time axis to be considered (not including hmax) */
171
172 unsigned int signature; /**< constraint signature which is need for pairwise comparison */
173
174 unsigned int validsignature:1; /**< is the signature valid */
175 unsigned int normalized:1; /**< is the constraint normalized */
176 unsigned int covercuts:1; /**< cover cuts are created? */
177 unsigned int propagated:1; /**< is constraint propagted */
178 unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
179 unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
180
181#ifdef SCIP_STATISTIC
182 int maxpeak;
183#endif
184};
185
186/** constraint handler data */
187struct SCIP_ConshdlrData
188{
189 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
190
191 SCIP_Bool usebinvars; /**< should the binary variables be used? */
192 SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
193 SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
194 SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
195 SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
196 SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
197 SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
198 SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
199 SCIP_Bool localcuts; /**< should cuts be added only locally? */
200 SCIP_Bool usecovercuts; /**< should covering cuts be added? */
201 SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
202
203 SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
204
205 SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
206 SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
207 SCIP_Bool normalize; /**< should demands and capacity be normalized? */
208 SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
209 SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
210 SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
211 SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
212 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
213 SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
214
215 SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
216
217 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
218
219 /* statistic values which are collected if SCIP_STATISTIC is defined */
220#ifdef SCIP_STATISTIC
221 SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
222 SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
223 SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
224 SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
225 SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
226 SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
227 SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
228 SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
229 SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
230 SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
231
232 int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
233 int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
234 int nremovedlocks; /**< number of times a up or down lock was removed */
235 int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
236 int ndecomps; /**< number of times a constraint was decomposed */
237 int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
238 int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
239 int naddedvarbounds; /**< number of added variable bounds constraints */
240 int naddeddisjunctives; /**< number of added disjunctive constraints */
241
242 SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
243#endif
244};
245
246/**@name Inference Information Methods
247 *
248 * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
249 * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
250 * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
251 *
252 * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
253 * change and the earliest start and latest completion time of all jobs in the conflict set.
254 *
255 * @{
256 */
257
258/** Propagation rules */
260{
261 PROPRULE_0_INVALID = 0, /**< invalid inference information */
262 PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
263 PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
264 PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
266typedef enum Proprule PROPRULE;
267
268/** inference information */
269struct InferInfo
270{
271 union
272 {
273 /** struct to use the inference information */
274 struct
275 {
276 unsigned int proprule:2; /**< propagation rule that was applied */
277 unsigned int data1:15; /**< data field one */
278 unsigned int data2:15; /**< data field two */
279 } asbits;
280 int asint; /**< inference information as a single int value */
281 } val;
282};
283typedef struct InferInfo INFERINFO;
284
285/** converts an integer into an inference information */
286static
288 int i /**< integer to convert */
289 )
290{
291 INFERINFO inferinfo;
292
293 inferinfo.val.asint = i;
294
295 return inferinfo;
296}
297
298/** converts an inference information into an int */
299static
301 INFERINFO inferinfo /**< inference information to convert */
302 )
303{
304 return inferinfo.val.asint;
305}
306
307/** returns the propagation rule stored in the inference information */
308static
310 INFERINFO inferinfo /**< inference information to convert */
311 )
312{
313 return (PROPRULE) inferinfo.val.asbits.proprule;
314}
315
316/** returns data field one of the inference information */
317static
319 INFERINFO inferinfo /**< inference information to convert */
320 )
321{
322 return (int) inferinfo.val.asbits.data1;
323}
324
325/** returns data field two of the inference information */
326static
328 INFERINFO inferinfo /**< inference information to convert */
329 )
330{
331 return (int) inferinfo.val.asbits.data2;
332}
333
334/** returns whether the inference information is valid */
335static
337 INFERINFO inferinfo /**< inference information to convert */
338 )
339{
340 return (inferinfo.val.asint != 0);
341}
342
343
344/** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
345static
347 PROPRULE proprule, /**< propagation rule that deduced the value */
348 int data1, /**< data field one */
349 int data2 /**< data field two */
350 )
351{
352 INFERINFO inferinfo;
353
354 /* check that the data members are in the range of the available bits */
355 if( proprule == PROPRULE_0_INVALID || data1 < 0 || data1 >= (1<<15) || data2 < 0 || data2 >= (1<<15) )
356 {
357 inferinfo.val.asint = 0;
358 assert(inferInfoGetProprule(inferinfo) == PROPRULE_0_INVALID);
359 assert(inferInfoIsValid(inferinfo) == FALSE);
360 }
361 else
362 {
363 inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
364 inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
365 inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
366 assert(inferInfoIsValid(inferinfo) == TRUE);
367 }
368
369 return inferinfo;
370}
371
372/**@} */
373
374/*
375 * Local methods
376 */
377
378/**@name Miscellaneous Methods
379 *
380 * @{
381 */
382
383#ifndef NDEBUG
384
385/** compute the core of a job which lies in certain interval [begin, end) */
386static
388 int begin, /**< begin of the interval */
389 int end, /**< end of the interval */
390 int ect, /**< earliest completion time */
391 int lst /**< latest start time */
392 )
393{
394 int core;
395
396 core = MAX(0, MIN(end, ect) - MAX(lst, begin));
397
398 return core;
399}
400#else
401#define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
402#endif
403
404/** returns the implied earliest start time */ /*lint -e{715}*/
405static
407 SCIP* scip, /**< SCIP data structure */
408 SCIP_VAR* var, /**< variable for which the implied est should be returned */
409 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
410 int* est /**< pointer to store the implied earliest start time */
411 )
412{ /*lint --e{715}*/
413#ifdef SCIP_DISABLED_CODE
414 /* there is a bug below */
415 SCIP_VAR** vbdvars;
416 SCIP_VAR* vbdvar;
417 SCIP_Real* vbdcoefs;
418 SCIP_Real* vbdconsts;
419 void* image;
420 int nvbdvars;
421 int v;
422#endif
423
425
426#ifdef SCIP_DISABLED_CODE
427 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
428
429 nvbdvars = SCIPvarGetNVlbs(var);
430 vbdvars = SCIPvarGetVlbVars(var);
431 vbdcoefs = SCIPvarGetVlbCoefs(var);
432 vbdconsts = SCIPvarGetVlbConstants(var);
433
434 for( v = 0; v < nvbdvars; ++v )
435 {
436 vbdvar = vbdvars[v];
437 assert(vbdvar != NULL);
438
439 image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
440
441 if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
442 {
443 int duration;
444 int vbdconst;
445
446 duration = (int)(size_t)image;
447 vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
448
449 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
451 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
452
453 if( duration >= vbdconst )
454 {
455 int impliedest;
456
457 impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
458
459 if( (*est) < impliedest )
460 {
461 (*est) = impliedest;
462
463 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
464 }
465 }
466 }
467 }
468#endif
469
470 return SCIP_OKAY;
471}
472
473/** returns the implied latest completion time */ /*lint -e{715}*/
474static
476 SCIP* scip, /**< SCIP data structure */
477 SCIP_VAR* var, /**< variable for which the implied est should be returned */
478 int duration, /**< duration of the given job */
479 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
480 int* lct /**< pointer to store the implied latest completion time */
481 )
482{ /*lint --e{715}*/
483#ifdef SCIP_DISABLED_CODE
484 /* there is a bug below */
485 SCIP_VAR** vbdvars;
486 SCIP_VAR* vbdvar;
487 SCIP_Real* vbdcoefs;
488 SCIP_Real* vbdconsts;
489 int nvbdvars;
490 int v;
491#endif
492
493 (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
494
495#ifdef SCIP_DISABLED_CODE
496 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
497
498 nvbdvars = SCIPvarGetNVubs(var);
499 vbdvars = SCIPvarGetVubVars(var);
500 vbdcoefs = SCIPvarGetVubCoefs(var);
501 vbdconsts = SCIPvarGetVubConstants(var);
502
503 for( v = 0; v < nvbdvars; ++v )
504 {
505 vbdvar = vbdvars[v];
506 assert(vbdvar != NULL);
507
508 if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
509 {
510 int vbdconst;
511
512 vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
513
514 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
516 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
517
518 if( duration >= -vbdconst )
519 {
520 int impliedlct;
521
522 impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
523
524 if( (*lct) > impliedlct )
525 {
526 (*lct) = impliedlct;
527
528 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
529 }
530 }
531 }
532 }
533#endif
534
535 return SCIP_OKAY;
536}
537
538/** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
539static
541 SCIP* scip, /**< SCIP data structure */
542 SCIP_CONSDATA* consdata, /**< constraint data */
543 SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
544 int** coefs, /**< pointer to store the coefficients */
545 int* nvars, /**< number if collect binary variables */
546 int* startindices, /**< permutation with rspect to the start times */
547 int curtime, /**< current point in time */
548 int nstarted, /**< number of jobs that start before the curtime or at curtime */
549 int nfinished /**< number of jobs that finished before curtime or at curtime */
550 )
551{
552 int nrowvars;
553 int startindex;
554 int size;
555
556 size = 10;
557 nrowvars = 0;
558 startindex = nstarted - 1;
559
560 SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
561 SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
562
563 /* search for the (nstarted - nfinished) jobs which are active at curtime */
564 while( nstarted - nfinished > nrowvars )
565 {
566 SCIP_VAR* var;
567 int endtime;
568 int duration;
569 int demand;
570 int varidx;
571
572 /* collect job information */
573 varidx = startindices[startindex];
574 assert(varidx >= 0 && varidx < consdata->nvars);
575
576 var = consdata->vars[varidx];
577 duration = consdata->durations[varidx];
578 demand = consdata->demands[varidx];
579 assert(var != NULL);
580
581 endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
582
583 /* check the end time of this job is larger than the curtime; in this case the job is still running */
584 if( endtime > curtime )
585 {
586 SCIP_VAR** binvars;
587 SCIP_Real* vals;
588 int nbinvars;
589 int start;
590 int end;
591 int b;
592
593 /* check if the linking constraints exists */
594 assert(SCIPexistsConsLinking(scip, var));
595 assert(SCIPgetConsLinking(scip, var) != NULL);
596 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
597
598 /* collect linking constraint information */
599 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
600 vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
601
602 start = curtime - duration + 1;
603 end = MIN(curtime, endtime - duration);
604
605 for( b = 0; b < nbinvars; ++b )
606 {
607 if( vals[b] < start )
608 continue;
609
610 if( vals[b] > end )
611 break;
612
613 assert(binvars[b] != NULL);
614
615 /* ensure array proper array size */
616 if( size == *nvars )
617 {
618 size *= 2;
619 SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
620 SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
621 }
622
623 (*vars)[*nvars] = binvars[b];
624 (*coefs)[*nvars] = demand;
625 (*nvars)++;
626 }
627 nrowvars++;
628 }
629
630 startindex--;
631 }
632
633 return SCIP_OKAY;
634}
635
636/** collect all integer variable which belong to jobs which can run at the point of interest */
637static
639 SCIP* scip, /**< SCIP data structure */
640 SCIP_CONSDATA* consdata, /**< constraint data */
641 SCIP_VAR*** activevars, /**< jobs that are currently running */
642 int* startindices, /**< permutation with rspect to the start times */
643 int curtime, /**< current point in time */
644 int nstarted, /**< number of jobs that start before the curtime or at curtime */
645 int nfinished, /**< number of jobs that finished before curtime or at curtime */
646 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
647 int* lhs /**< lhs for the new row sum of lbs + minoffset */
648 )
649{
650 SCIP_VAR* var;
651 int startindex;
652 int endtime;
653 int duration;
654 int starttime;
655
656 int varidx;
657 int sumofstarts;
658 int mindelta;
659 int counter;
660
661 assert(curtime >= consdata->hmin);
662 assert(curtime < consdata->hmax);
663
664 counter = 0;
665 sumofstarts = 0;
666
667 mindelta = INT_MAX;
668
669 startindex = nstarted - 1;
670
671 /* search for the (nstarted - nfinished) jobs which are active at curtime */
672 while( nstarted - nfinished > counter )
673 {
674 assert(startindex >= 0);
675
676 /* collect job information */
677 varidx = startindices[startindex];
678 assert(varidx >= 0 && varidx < consdata->nvars);
679
680 var = consdata->vars[varidx];
681 duration = consdata->durations[varidx];
682 assert(duration > 0);
683 assert(var != NULL);
684
685 if( lower )
687 else
689
690 endtime = MIN(starttime + duration, consdata->hmax);
691
692 /* check the end time of this job is larger than the curtime; in this case the job is still running */
693 if( endtime > curtime )
694 {
695 (*activevars)[counter] = var;
696 sumofstarts += starttime;
697 mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
698 counter++;
699 }
700
701 startindex--;
702 }
703
704 assert(mindelta > 0);
705 *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
706
707 return SCIP_OKAY;
708}
709
710/** initialize the sorted event point arrays */
711static
713 SCIP* scip, /**< SCIP data structure */
714 int nvars, /**< number of start time variables (activities) */
715 SCIP_VAR** vars, /**< array of start time variables */
716 int* durations, /**< array of durations per start time variable */
717 int* starttimes, /**< array to store sorted start events */
718 int* endtimes, /**< array to store sorted end events */
719 int* startindices, /**< permutation with rspect to the start times */
720 int* endindices, /**< permutation with rspect to the end times */
721 SCIP_Bool local /**< shall local bounds be used */
722 )
723{
724 SCIP_VAR* var;
725 int j;
726
727 assert(vars != NULL || nvars == 0);
728
729 /* assign variables, start and endpoints to arrays */
730 for ( j = 0; j < nvars; ++j )
731 {
732 assert(vars != NULL);
733
734 var = vars[j];
735 assert(var != NULL);
736
737 if( local )
738 starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
739 else
740 starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
741
742 startindices[j] = j;
743
744 if( local )
745 endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
746 else
747 endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
748
749 endindices[j] = j;
750 }
751
752 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
753 SCIPsortIntInt(starttimes, startindices, j);
754 SCIPsortIntInt(endtimes, endindices, j);
755}
756
757/** initialize the sorted event point arrays w.r.t. the given primal solutions */
758static
760 SCIP* scip, /**< SCIP data structure */
761 SCIP_SOL* sol, /**< solution */
762 int nvars, /**< number of start time variables (activities) */
763 SCIP_VAR** vars, /**< array of start time variables */
764 int* durations, /**< array of durations per start time variable */
765 int* starttimes, /**< array to store sorted start events */
766 int* endtimes, /**< array to store sorted end events */
767 int* startindices, /**< permutation with rspect to the start times */
768 int* endindices /**< permutation with rspect to the end times */
769 )
770{
771 SCIP_VAR* var;
772 int j;
773
774 assert(vars != NULL || nvars == 0);
775
776 /* assign variables, start and endpoints to arrays */
777 for ( j = 0; j < nvars; ++j )
778 {
779 assert(vars != NULL);
780
781 var = vars[j];
782 assert(var != NULL);
783
784 starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
785 startindices[j] = j;
786
787 endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
788 endindices[j] = j;
789 }
790
791 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
792 SCIPsortIntInt(starttimes, startindices, j);
793 SCIPsortIntInt(endtimes, endindices, j);
794}
795
796/** initialize the sorted event point arrays
797 *
798 * @todo Check the separation process!
799 */
800static
802 SCIP* scip, /**< SCIP data structure */
803 SCIP_CONSDATA* consdata, /**< constraint data */
804 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
805 int* starttimes, /**< array to store sorted start events */
806 int* endtimes, /**< array to store sorted end events */
807 int* startindices, /**< permutation with rspect to the start times */
808 int* endindices, /**< permutation with rspect to the end times */
809 int* nvars, /**< number of variables that are integral */
810 SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
811 )
812{
813 SCIP_VAR* var;
814 int tmpnvars;
815 int j;
816
817 tmpnvars = consdata->nvars;
818 *nvars = 0;
819
820 /* assign variables, start and endpoints to arrays */
821 for ( j = 0; j < tmpnvars; ++j )
822 {
823 var = consdata->vars[j];
824 assert(var != NULL);
825 assert(consdata->durations[j] > 0);
826 assert(consdata->demands[j] > 0);
827
828 if( lower )
829 {
830 /* only consider jobs that are at their lower or upper bound */
831 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
832 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
833 continue;
834
835 starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
836 startindices[*nvars] = j;
837
838 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
839 endindices[*nvars] = j;
840
841 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
842 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
843 consdata->durations[j],
844 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
845 consdata->demands[startindices[*nvars]]);
846
847 (*nvars)++;
848 }
849 else
850 {
851 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
852 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
853 continue;
854
855 starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
856 startindices[*nvars] = j;
857
858 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
859 endindices[*nvars] = j;
860
861 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
862 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
863 consdata->durations[j],
864 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
865 consdata->demands[startindices[*nvars]]);
866
867 (*nvars)++;
868 }
869 }
870
871 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
872 SCIPsortIntInt(starttimes, startindices, *nvars);
873 SCIPsortIntInt(endtimes, endindices, *nvars);
874
875#ifdef SCIP_DEBUG
876 SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
877
878 for ( j = 0; j < *nvars; ++j )
879 {
880 SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
881 startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
882 consdata->demands[startindices[j]]);
883 }
884
885 for ( j = 0; j < *nvars; ++j )
886 {
887 SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
888 consdata->demands[endindices[j]]);
889 }
890#endif
891}
892
893#ifdef SCIP_STATISTIC
894/** this method checks for relevant intervals for energetic reasoning */
895static
896SCIP_RETCODE computeRelevantEnergyIntervals(
897 SCIP* scip, /**< SCIP data structure */
898 int nvars, /**< number of start time variables (activities) */
899 SCIP_VAR** vars, /**< array of start time variables */
900 int* durations, /**< array of durations */
901 int* demands, /**< array of demands */
902 int capacity, /**< cumulative capacity */
903 int hmin, /**< left bound of time axis to be considered (including hmin) */
904 int hmax, /**< right bound of time axis to be considered (not including hmax) */
905 int** timepoints, /**< array to store relevant points in time */
906 SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
907 int* ntimepoints, /**< pointer to store the number of timepoints */
908 int* maxdemand, /**< pointer to store maximum over all demands */
909 SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
910 )
911{
912 int* starttimes; /* stores when each job is starting */
913 int* endtimes; /* stores when each job ends */
914 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
915 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
916
917 SCIP_Real totaldemand;
918 int curtime; /* point in time which we are just checking */
919 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
920
921 int j;
922
923 assert( scip != NULL );
924 assert(durations != NULL);
925 assert(demands != NULL);
926 assert(capacity >= 0);
927
928 /* if no activities are associated with this cumulative then this constraint is redundant */
929 if( nvars == 0 )
930 return SCIP_OKAY;
931
932 assert(vars != NULL);
933
934 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
935 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
936 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
937 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
938
939 /* create event point arrays */
940 createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
941
942 endindex = 0;
943 totaldemand = 0.0;
944
945 *ntimepoints = 0;
946 (*timepoints)[0] = starttimes[0];
947 (*cumulativedemands)[0] = 0;
948 *maxdemand = 0;
949
950 /* check each startpoint of a job whether the capacity is kept or not */
951 for( j = 0; j < nvars; ++j )
952 {
953 int lct;
954 int idx;
955
956 curtime = starttimes[j];
957
958 if( curtime >= hmax )
959 break;
960
961 /* free all capacity usages of jobs the are no longer running */
962 while( endindex < nvars && endtimes[endindex] <= curtime )
963 {
964 int est;
965
966 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
967 {
968 (*ntimepoints)++;
969 (*timepoints)[*ntimepoints] = endtimes[endindex];
970 (*cumulativedemands)[*ntimepoints] = 0;
971 }
972
973 idx = endindices[endindex];
975 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
976 endindex++;
977
978 (*cumulativedemands)[*ntimepoints] = totaldemand;
979 }
980
981 idx = startindices[j];
982 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
983 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
984
985 if( (*timepoints)[*ntimepoints] < curtime )
986 {
987 (*ntimepoints)++;
988 (*timepoints)[*ntimepoints] = curtime;
989 (*cumulativedemands)[*ntimepoints] = 0;
990 }
991
992 (*cumulativedemands)[*ntimepoints] = totaldemand;
993
994 /* add the relative capacity requirements for all job which start at the curtime */
995 while( j+1 < nvars && starttimes[j+1] == curtime )
996 {
997 ++j;
998 idx = startindices[j];
999 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
1000 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
1001
1002 (*cumulativedemands)[*ntimepoints] = totaldemand;
1003 }
1004 } /*lint --e{850}*/
1005
1006 /* free all capacity usages of jobs that are no longer running */
1007 while( endindex < nvars/* && endtimes[endindex] < hmax*/)
1008 {
1009 int est;
1010 int idx;
1011
1012 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
1013 {
1014 (*ntimepoints)++;
1015 (*timepoints)[*ntimepoints] = endtimes[endindex];
1016 (*cumulativedemands)[*ntimepoints] = 0;
1017 }
1018
1019 idx = endindices[endindex];
1020 est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
1021 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
1022 (*cumulativedemands)[*ntimepoints] = totaldemand;
1023
1024 ++endindex;
1025 }
1026
1027 (*ntimepoints)++;
1028 /* compute minimum free capacity */
1029 (*minfreecapacity) = INT_MAX;
1030 for( j = 0; j < *ntimepoints; ++j )
1031 {
1032 if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1033 *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1034 }
1035
1036 /* free buffer arrays */
1037 SCIPfreeBufferArray(scip, &endindices);
1038 SCIPfreeBufferArray(scip, &startindices);
1039 SCIPfreeBufferArray(scip, &endtimes);
1040 SCIPfreeBufferArray(scip, &starttimes);
1041
1042 return SCIP_OKAY;
1043}
1044
1045/** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1046static
1047SCIP_RETCODE evaluateCumulativeness(
1048 SCIP* scip, /**< pointer to scip */
1049 SCIP_CONS* cons /**< cumulative constraint */
1050 )
1051{
1052 SCIP_CONSDATA* consdata;
1053 int nvars;
1054 int v;
1055 int capacity;
1056
1057 /* output values: */
1058 SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1059 SCIP_Real cumfactor1;
1060 SCIP_Real resstrength1; /* overall strength */
1061 SCIP_Real resstrength2; /* timepoint wise maximum */
1062
1063 /* helpful variables: */
1064 SCIP_Real globalpeak;
1065 SCIP_Real globalmaxdemand;
1066
1067 /* get constraint data structure */
1068 consdata = SCIPconsGetData(cons);
1069 assert(consdata != NULL);
1070
1071 nvars = consdata->nvars;
1072 capacity = consdata->capacity;
1073 globalpeak = 0.0;
1074 globalmaxdemand = 0.0;
1075
1076 disjfactor2 = 0.0;
1077 cumfactor1 = 0.0;
1078 resstrength2 = 0.0;
1079
1080 /* check each starting time (==each job, but inefficient) */
1081 for( v = 0; v < nvars; ++v )
1082 {
1083 SCIP_Real peak;
1084 SCIP_Real maxdemand;
1085 SCIP_Real deltademand;
1086 int ndemands;
1087 int nlarge;
1088
1089 int timepoint;
1090 int j;
1091 timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1092 peak = consdata->demands[v];
1093 ndemands = 1;
1094 maxdemand = 0;
1095 nlarge = 0;
1096
1097 if( consdata->demands[v] > capacity / 3 )
1098 nlarge++;
1099
1100 for( j = 0; j < nvars; ++j )
1101 {
1102 int lb;
1103
1104 if( j == v )
1105 continue;
1106
1107 maxdemand = 0.0;
1108 lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1109
1110 if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1111 {
1112 peak += consdata->demands[j];
1113 ndemands++;
1114
1115 if( consdata->demands[j] > consdata->capacity / 3 )
1116 nlarge++;
1117 }
1118 }
1119
1120 deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1121 globalpeak = MAX(globalpeak, peak);
1122 globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1123
1124 if( peak > capacity )
1125 {
1126 disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1127 cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1128 resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1129 }
1130 }
1131
1132 resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1133
1134 consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1135 consdata->disjfactor2 = disjfactor2;
1136 consdata->cumfactor1 = cumfactor1;
1137 consdata->resstrength2 = resstrength2;
1138 consdata->resstrength1 = resstrength1;
1139
1140 /* get estimated res strength */
1141 {
1142 int* timepoints;
1143 SCIP_Real* estimateddemands;
1144 int ntimepoints;
1145 int maxdemand;
1146 SCIP_Real minfreecapacity;
1147
1148 SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1149 SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1150
1151 ntimepoints = 0;
1152 minfreecapacity = INT_MAX;
1153
1154 SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1155 consdata->durations, consdata->demands,
1156 capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1157 &ntimepoints, &maxdemand, &minfreecapacity) );
1158
1159 /* free buffer arrays */
1160 SCIPfreeBufferArray(scip, &estimateddemands);
1161 SCIPfreeBufferArray(scip, &timepoints);
1162
1163 consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1164 }
1165
1166 SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1167 SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1168 consdata->estimatedstrength);
1169
1170 return SCIP_OKAY;
1171}
1172#endif
1173
1174/** gets the active variables together with the constant */
1175static
1177 SCIP* scip, /**< SCIP data structure */
1178 SCIP_VAR** var, /**< pointer to store the active variable */
1179 int* scalar, /**< pointer to store the scalar */
1180 int* constant /**< pointer to store the constant */
1181 )
1182{
1183 if( !SCIPvarIsActive(*var) )
1184 {
1185 SCIP_Real realscalar;
1186 SCIP_Real realconstant;
1187
1188 realscalar = 1.0;
1189 realconstant = 0.0;
1190
1192
1193 /* transform variable to active variable */
1194 SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1195 assert(!SCIPisZero(scip, realscalar));
1196 assert(SCIPvarIsActive(*var));
1197
1198 if( realconstant < 0.0 )
1199 (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1200 else
1201 (*constant) = SCIPconvertRealToInt(scip, realconstant);
1202
1203 if( realscalar < 0.0 )
1204 (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1205 else
1206 (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1207 }
1208 else
1209 {
1210 (*scalar) = 1;
1211 (*constant) = 0;
1212 }
1213
1214 assert(*scalar != 0);
1215
1216 return SCIP_OKAY;
1217}
1218
1219/** computes the total energy of all jobs */
1220static
1222 int* durations, /**< array of job durations */
1223 int* demands, /**< array of job demands */
1224 int njobs /**< number of jobs */
1225 )
1226{
1227 SCIP_Longint energy;
1228 int j;
1229
1230 energy = 0;
1231
1232 for( j = 0; j < njobs; ++j )
1233 energy += (SCIP_Longint) durations[j] * demands[j];
1234
1235 return energy;
1236}
1237
1238/**@} */
1239
1240/**@name Default method to solve a cumulative condition
1241 *
1242 * @{
1243 */
1244
1245/** setup and solve subscip to solve single cumulative condition */
1246static
1248 SCIP* subscip, /**< subscip data structure */
1249 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1250 int* durations, /**< array of durations */
1251 int* demands, /**< array of demands */
1252 int njobs, /**< number of jobs (activities) */
1253 int capacity, /**< cumulative capacity */
1254 int hmin, /**< left bound of time axis to be considered (including hmin) */
1255 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1256 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1257 SCIP_Real timelimit, /**< time limit for solving in seconds */
1258 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1259 SCIP_Real* ests, /**< array of earliest start times for each job */
1260 SCIP_Real* lsts, /**< array of latest start times for each job */
1261 SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1262 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1263 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1264 SCIP_Bool* error /**< pointer to store if an error occurred */
1265 )
1266{
1267 SCIP_VAR** subvars;
1268 SCIP_CONS* cons;
1269
1270 char name[SCIP_MAXSTRLEN];
1271 int v;
1272 SCIP_RETCODE retcode;
1273
1274 assert(subscip != NULL);
1275
1276 /* copy all plugins */
1278
1279 /* create the subproblem */
1280 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1281
1282 SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1283
1284 /* create for each job a start time variable */
1285 for( v = 0; v < njobs; ++v )
1286 {
1287 SCIP_Real objval;
1288
1289 /* construct variable name */
1290 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1291
1292 if( objvals == NULL )
1293 objval = 0.0;
1294 else
1295 objval = objvals[v];
1296
1297 SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1298 SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1299 }
1300
1301 /* create cumulative constraint */
1302 SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1303 njobs, subvars, durations, demands, capacity) );
1304
1305 /* set effective horizon */
1306 SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1307 SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1308
1309 /* add cumulative constraint */
1310 SCIP_CALL( SCIPaddCons(subscip, cons) );
1311 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1312
1313 /* set CP solver settings
1314 *
1315 * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1316 * time limit.
1317 */
1319
1320 /* do not abort subproblem on CTRL-C */
1321 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1322
1323 /* disable output to console */
1324 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1325
1326 /* set limits for the subproblem */
1327 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1328 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1329 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1330
1331 /* forbid recursive call of heuristics and separators solving subMIPs */
1332 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1333
1334 /* solve single cumulative constraint by branch and bound */
1335 retcode = SCIPsolve(subscip);
1336
1337 if( retcode != SCIP_OKAY )
1338 (*error) = TRUE;
1339 else
1340 {
1341 SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1342
1343 /* evaluated solution status */
1344 switch( SCIPgetStatus(subscip) )
1345 {
1348 (*infeasible) = TRUE;
1349 (*solved) = TRUE;
1350 break;
1352 (*unbounded) = TRUE;
1353 (*solved) = TRUE;
1354 break;
1356 {
1357 SCIP_SOL* sol;
1358 SCIP_Real solval;
1359
1360 sol = SCIPgetBestSol(subscip);
1361 assert(sol != NULL);
1362
1363 for( v = 0; v < njobs; ++v )
1364 {
1365 solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1366
1367 ests[v] = solval;
1368 lsts[v] = solval;
1369 }
1370 (*solved) = TRUE;
1371 break;
1372 }
1379 /* transfer the global bound changes */
1380 for( v = 0; v < njobs; ++v )
1381 {
1382 ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1383 lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1384 }
1385 (*solved) = FALSE;
1386 break;
1387
1396 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1397 return SCIP_INVALIDDATA;
1398 }
1399 }
1400
1401 /* release all variables */
1402 for( v = 0; v < njobs; ++v )
1403 {
1404 SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1405 }
1406
1407 SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1408
1409 return SCIP_OKAY;
1410}
1411
1412/** solve single cumulative condition using SCIP and a single cumulative constraint */
1413static
1414SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1415{
1416 SCIP* subscip;
1417
1418 SCIP_RETCODE retcode;
1419
1420 assert(njobs > 0);
1421
1422 (*solved) = FALSE;
1423 (*infeasible) = FALSE;
1424 (*unbounded) = FALSE;
1425 (*error) = FALSE;
1426
1427 SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1428
1429 /* initialize the sub-problem */
1430 SCIP_CALL( SCIPcreate(&subscip) );
1431
1432 /* create and solve the subproblem. catch possible errors */
1433 retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1434 njobs, capacity, hmin, hmax,
1435 maxnodes, timelimit, memorylimit,
1436 ests, lsts,
1437 infeasible, unbounded, solved, error);
1438
1439 /* free the subscip in any case */
1440 SCIP_CALL( SCIPfree(&subscip) );
1441
1442 SCIP_CALL( retcode );
1443
1444 return SCIP_OKAY;
1445}
1446
1447#ifdef SCIP_DISABLED_CODE
1448/* The following code should work, but is currently not used. */
1449
1450/** solve single cumulative condition using SCIP and the time indexed formulation */
1451static
1452SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1453{
1454 SCIP* subscip;
1455 SCIP_VAR*** binvars;
1456 SCIP_RETCODE retcode;
1457 char name[SCIP_MAXSTRLEN];
1458 int minest;
1459 int maxlct;
1460 int t;
1461 int v;
1462
1463 assert(njobs > 0);
1464
1465 (*solved) = FALSE;
1466 (*infeasible) = FALSE;
1467 (*unbounded) = FALSE;
1468 (*error) = FALSE;
1469
1470 SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1471
1472 /* initialize the sub-problem */
1473 SCIP_CALL( SCIPcreate(&subscip) );
1474
1475 /* copy all plugins */
1477
1478 /* create the subproblem */
1479 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1480
1481 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1482
1483 minest = INT_MAX;
1484 maxlct = INT_MIN;
1485
1486 /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1487 * partitioning constrain which forces that job starts
1488 */
1489 for( v = 0; v < njobs; ++v )
1490 {
1491 SCIP_CONS* cons;
1492 SCIP_Real objval;
1493 int timeinterval;
1494 int est;
1495 int lst;
1496
1497 if( objvals == NULL )
1498 objval = 0.0;
1499 else
1500 objval = objvals[v];
1501
1502 est = ests[v];
1503 lst = lsts[v];
1504
1505 /* compute number of possible start points */
1506 timeinterval = lst - est + 1;
1507 assert(timeinterval > 0);
1508
1509 /* compute the smallest earliest start time and largest latest completion time */
1510 minest = MIN(minest, est);
1511 maxlct = MAX(maxlct, lst + durations[v]);
1512
1513 /* construct constraint name */
1514 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1515
1516 SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1517
1518 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1519
1520 for( t = 0; t < timeinterval; ++t )
1521 {
1522 SCIP_VAR* binvar;
1523
1524 /* construct varibale name */
1525 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1526
1527 SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1528 SCIP_CALL( SCIPaddVar(subscip, binvar) );
1529
1530 /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1531 SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1532
1533 binvars[v][t] = binvar;
1534 }
1535
1536 /* add and release the set partitioning constraint */
1537 SCIP_CALL( SCIPaddCons(subscip, cons) );
1538 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1539 }
1540
1541 /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1542 hmin = MAX(hmin, minest);
1543 hmax = MIN(hmax, maxlct);
1544 assert(hmin > INT_MIN);
1545 assert(hmax < INT_MAX);
1546 assert(hmin < hmax);
1547
1548 /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1549 for( t = hmin; t < hmax; ++t )
1550 {
1551 SCIP_CONS* cons;
1552
1553 /* construct constraint name */
1554 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1555
1556 /* create an empty knapsack constraint */
1557 SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1558
1559 /* add all jobs which potentially can be processed at that time point */
1560 for( v = 0; v < njobs; ++v )
1561 {
1562 int duration;
1563 int demand;
1564 int start;
1565 int end;
1566 int est;
1567 int lst;
1568 int k;
1569
1570 est = ests[v];
1571 lst = lsts[v] ;
1572
1573 duration = durations[v];
1574 assert(duration > 0);
1575
1576 /* check if the varibale is processed potentially at time point t */
1577 if( t < est || t >= lst + duration )
1578 continue;
1579
1580 demand = demands[v];
1581 assert(demand >= 0);
1582
1583 start = MAX(t - duration + 1, est);
1584 end = MIN(t, lst);
1585
1586 assert(start <= end);
1587
1588 for( k = start; k <= end; ++k )
1589 {
1590 assert(binvars[v][k] != NULL);
1591 SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1592 }
1593 }
1594
1595 /* add and release the knapsack constraint */
1596 SCIP_CALL( SCIPaddCons(subscip, cons) );
1597 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1598 }
1599
1600 /* do not abort subproblem on CTRL-C */
1601 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1602
1603 /* disable output to console */
1604 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1605
1606 /* set limits for the subproblem */
1607 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1608 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1609 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1610
1611 /* solve single cumulative constraint by branch and bound */
1612 retcode = SCIPsolve(subscip);
1613
1614 if( retcode != SCIP_OKAY )
1615 (*error) = TRUE;
1616 else
1617 {
1618 SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1619
1620 /* evaluated solution status */
1621 switch( SCIPgetStatus(subscip) )
1622 {
1625 (*infeasible) = TRUE;
1626 (*solved) = TRUE;
1627 break;
1629 (*unbounded) = TRUE;
1630 (*solved) = TRUE;
1631 break;
1633 {
1634 SCIP_SOL* sol;
1635
1636 sol = SCIPgetBestSol(subscip);
1637 assert(sol != NULL);
1638
1639 for( v = 0; v < njobs; ++v )
1640 {
1641 int timeinterval;
1642 int est;
1643 int lst;
1644
1645 est = ests[v];
1646 lst = lsts[v];
1647
1648 /* compute number of possible start points */
1649 timeinterval = lst - est + 1;
1650
1651 /* check which binary varibale is set to one */
1652 for( t = 0; t < timeinterval; ++t )
1653 {
1654 if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1655 {
1656 ests[v] = est + t;
1657 lsts[v] = est + t;
1658 break;
1659 }
1660 }
1661 }
1662
1663 (*solved) = TRUE;
1664 break;
1665 }
1671 /* transfer the global bound changes */
1672 for( v = 0; v < njobs; ++v )
1673 {
1674 int timeinterval;
1675 int est;
1676 int lst;
1677
1678 est = ests[v];
1679 lst = lsts[v];
1680
1681 /* compute number of possible start points */
1682 timeinterval = lst - est + 1;
1683
1684 /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1685 for( t = 0; t < timeinterval; ++t )
1686 {
1687 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1688 {
1689 ests[v] = est + t;
1690 break;
1691 }
1692 }
1693
1694 /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1695 for( t = timeinterval - 1; t >= 0; --t )
1696 {
1697 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1698 {
1699 lsts[v] = est + t;
1700 break;
1701 }
1702 }
1703 }
1704 (*solved) = FALSE;
1705 break;
1706
1712 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1713 return SCIP_INVALIDDATA;
1714 }
1715 }
1716
1717 /* release all variables */
1718 for( v = 0; v < njobs; ++v )
1719 {
1720 int timeinterval;
1721 int est;
1722 int lst;
1723
1724 est = ests[v];
1725 lst = lsts[v];
1726
1727 /* compute number of possible start points */
1728 timeinterval = lst - est + 1;
1729
1730 for( t = 0; t < timeinterval; ++t )
1731 {
1732 SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1733 }
1734 SCIPfreeBufferArray(subscip, &binvars[v]);
1735 }
1736
1737 SCIPfreeBufferArray(subscip, &binvars);
1738
1739 SCIP_CALL( SCIPfree(&subscip) );
1740
1741 return SCIP_OKAY;
1742}
1743#endif
1744
1745/**@} */
1746
1747/**@name Constraint handler data
1748 *
1749 * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1750 * handler.
1751 *
1752 * @{
1753 */
1754
1755/** creates constaint handler data for cumulative constraint handler */
1756static
1758 SCIP* scip, /**< SCIP data structure */
1759 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1760 SCIP_EVENTHDLR* eventhdlr /**< event handler */
1761 )
1762{
1763 /* create precedence constraint handler data */
1764 assert(scip != NULL);
1765 assert(conshdlrdata != NULL);
1766 assert(eventhdlr != NULL);
1767
1768 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1769
1770 /* set event handler for checking if bounds of start time variables are tighten */
1771 (*conshdlrdata)->eventhdlr = eventhdlr;
1772
1773 /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1774 (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1775
1776#ifdef SCIP_STATISTIC
1777 (*conshdlrdata)->nlbtimetable = 0;
1778 (*conshdlrdata)->nubtimetable = 0;
1779 (*conshdlrdata)->ncutofftimetable = 0;
1780 (*conshdlrdata)->nlbedgefinder = 0;
1781 (*conshdlrdata)->nubedgefinder = 0;
1782 (*conshdlrdata)->ncutoffedgefinder = 0;
1783 (*conshdlrdata)->ncutoffoverload = 0;
1784 (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1785
1786 (*conshdlrdata)->nirrelevantjobs = 0;
1787 (*conshdlrdata)->nalwaysruns = 0;
1788 (*conshdlrdata)->nremovedlocks = 0;
1789 (*conshdlrdata)->ndualfixs = 0;
1790 (*conshdlrdata)->ndecomps = 0;
1791 (*conshdlrdata)->ndualbranchs = 0;
1792 (*conshdlrdata)->nallconsdualfixs = 0;
1793 (*conshdlrdata)->naddedvarbounds = 0;
1794 (*conshdlrdata)->naddeddisjunctives = 0;
1795#endif
1796
1797 return SCIP_OKAY;
1798}
1799
1800/** frees constraint handler data for logic or constraint handler */
1801static
1803 SCIP* scip, /**< SCIP data structure */
1804 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1805 )
1806{
1807 assert(conshdlrdata != NULL);
1808 assert(*conshdlrdata != NULL);
1809
1810 SCIPfreeBlockMemory(scip, conshdlrdata);
1811}
1812
1813/**@} */
1814
1815
1816/**@name Constraint data methods
1817 *
1818 * @{
1819 */
1820
1821/** catches bound change events for all variables in transformed cumulative constraint */
1822static
1824 SCIP* scip, /**< SCIP data structure */
1825 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1826 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1827 )
1828{
1829 int v;
1830
1831 assert(scip != NULL);
1832 assert(consdata != NULL);
1833 assert(eventhdlr != NULL);
1834
1835 /* catch event for every single variable */
1836 for( v = 0; v < consdata->nvars; ++v )
1837 {
1838 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1839 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1840 }
1841
1842 return SCIP_OKAY;
1843}
1844
1845/** drops events for variable at given position */
1846static
1848 SCIP* scip, /**< SCIP data structure */
1849 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1850 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1851 int pos /**< array position of variable to catch bound change events for */
1852 )
1853{
1854 assert(scip != NULL);
1855 assert(consdata != NULL);
1856 assert(eventhdlr != NULL);
1857 assert(0 <= pos && pos < consdata->nvars);
1858 assert(consdata->vars[pos] != NULL);
1859
1860 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1861 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1862
1863 return SCIP_OKAY;
1864}
1865
1866/** drops bound change events for all variables in transformed linear constraint */
1867static
1869 SCIP* scip, /**< SCIP data structure */
1870 SCIP_CONSDATA* consdata, /**< linear constraint data */
1871 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1872 )
1873{
1874 int v;
1875
1876 assert(scip != NULL);
1877 assert(consdata != NULL);
1878
1879 /* drop event of every single variable */
1880 for( v = 0; v < consdata->nvars; ++v )
1881 {
1882 SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1883 }
1884
1885 return SCIP_OKAY;
1886}
1887
1888/** initialize variable lock data structure */
1889static
1891 SCIP_CONSDATA* consdata, /**< constraint data */
1892 SCIP_Bool locked /**< should the variable be locked? */
1893 )
1894{
1895 int nvars;
1896 int v;
1897
1898 nvars = consdata->nvars;
1899
1900 /* initialize locking arrays */
1901 for( v = 0; v < nvars; ++v )
1902 {
1903 consdata->downlocks[v] = locked;
1904 consdata->uplocks[v] = locked;
1905 }
1906}
1907
1908/** creates constraint data of cumulative constraint */
1909static
1911 SCIP* scip, /**< SCIP data structure */
1912 SCIP_CONSDATA** consdata, /**< pointer to consdata */
1913 SCIP_VAR** vars, /**< array of integer variables */
1914 SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1915 int* durations, /**< array containing corresponding durations */
1916 int* demands, /**< array containing corresponding demands */
1917 int nvars, /**< number of variables */
1918 int capacity, /**< available cumulative capacity */
1919 int hmin, /**< left bound of time axis to be considered (including hmin) */
1920 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1921 SCIP_Bool check /**< is the corresponding constraint a check constraint */
1922 )
1923{
1924 int v;
1925
1926 assert(scip != NULL);
1927 assert(consdata != NULL);
1928 assert(vars != NULL || nvars > 0);
1929 assert(demands != NULL);
1930 assert(durations != NULL);
1931 assert(capacity >= 0);
1932 assert(hmin >= 0);
1933 assert(hmin < hmax);
1934
1935 /* create constraint data */
1936 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1937
1938 (*consdata)->hmin = hmin;
1939 (*consdata)->hmax = hmax;
1940
1941 (*consdata)->capacity = capacity;
1942 (*consdata)->demandrows = NULL;
1943 (*consdata)->demandrowssize = 0;
1944 (*consdata)->ndemandrows = 0;
1945 (*consdata)->scoverrows = NULL;
1946 (*consdata)->nscoverrows = 0;
1947 (*consdata)->scoverrowssize = 0;
1948 (*consdata)->bcoverrows = NULL;
1949 (*consdata)->nbcoverrows = 0;
1950 (*consdata)->bcoverrowssize = 0;
1951 (*consdata)->nvars = nvars;
1952 (*consdata)->varssize = nvars;
1953 (*consdata)->signature = 0;
1954 (*consdata)->validsignature = FALSE;
1955 (*consdata)->normalized = FALSE;
1956 (*consdata)->covercuts = FALSE;
1957 (*consdata)->propagated = FALSE;
1958 (*consdata)->varbounds = FALSE;
1959 (*consdata)->triedsolving = FALSE;
1960
1961 if( nvars > 0 )
1962 {
1963 assert(vars != NULL); /* for flexelint */
1964
1965 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1966 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1967 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1968 (*consdata)->linkingconss = NULL;
1969
1970 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1971 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1972
1973 /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
1974 initializeLocks(*consdata, check);
1975
1976 if( linkingconss != NULL )
1977 {
1978 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1979 }
1980
1981 /* transform variables, if they are not yet transformed */
1982 if( SCIPisTransformed(scip) )
1983 {
1984 SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1985
1986 /* get transformed variables and do NOT captures these */
1987 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1988
1989 /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1990 * been multi-aggregated
1991 */
1992 for( v = 0; v < nvars; ++v )
1993 {
1994 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1995 }
1996
1997 if( linkingconss != NULL )
1998 {
1999 /* get transformed constraints and captures these */
2000 SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
2001
2002 for( v = 0; v < nvars; ++v )
2003 assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
2004 }
2005 }
2006
2007#ifndef NDEBUG
2008 /* only binary and integer variables can be used in cumulative constraints
2009 * for fractional variable values, the constraint cannot be checked
2010 */
2011 for( v = 0; v < (*consdata)->nvars; ++v )
2012 assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
2013#endif
2014 }
2015 else
2016 {
2017 (*consdata)->vars = NULL;
2018 (*consdata)->downlocks = NULL;
2019 (*consdata)->uplocks = NULL;
2020 (*consdata)->demands = NULL;
2021 (*consdata)->durations = NULL;
2022 (*consdata)->linkingconss = NULL;
2023 }
2024
2025 /* initialize values for running propagation algorithms efficiently */
2026 (*consdata)->resstrength1 = -1.0;
2027 (*consdata)->resstrength2 = -1.0;
2028 (*consdata)->cumfactor1 = -1.0;
2029 (*consdata)->disjfactor1 = -1.0;
2030 (*consdata)->disjfactor2 = -1.0;
2031 (*consdata)->estimatedstrength = -1.0;
2032
2033 SCIPstatistic( (*consdata)->maxpeak = -1 );
2034
2035 return SCIP_OKAY;
2036}
2037
2038/** releases LP rows of constraint data and frees rows array */
2039static
2041 SCIP* scip, /**< SCIP data structure */
2042 SCIP_CONSDATA** consdata /**< constraint data */
2043 )
2044{
2045 int r;
2046
2047 assert(consdata != NULL);
2048 assert(*consdata != NULL);
2049
2050 for( r = 0; r < (*consdata)->ndemandrows; ++r )
2051 {
2052 assert((*consdata)->demandrows[r] != NULL);
2053 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2054 }
2055
2056 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2057
2058 (*consdata)->ndemandrows = 0;
2059 (*consdata)->demandrowssize = 0;
2060
2061 /* free rows of cover cuts */
2062 for( r = 0; r < (*consdata)->nscoverrows; ++r )
2063 {
2064 assert((*consdata)->scoverrows[r] != NULL);
2065 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2066 }
2067
2068 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2069
2070 (*consdata)->nscoverrows = 0;
2071 (*consdata)->scoverrowssize = 0;
2072
2073 for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2074 {
2075 assert((*consdata)->bcoverrows[r] != NULL);
2076 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2077 }
2078
2079 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2080
2081 (*consdata)->nbcoverrows = 0;
2082 (*consdata)->bcoverrowssize = 0;
2083
2084 (*consdata)->covercuts = FALSE;
2085
2086 return SCIP_OKAY;
2087}
2088
2089/** frees a cumulative constraint data */
2090static
2092 SCIP* scip, /**< SCIP data structure */
2093 SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2094 )
2095{
2096 int varssize;
2097 int nvars;
2098
2099 assert(consdata != NULL);
2100 assert(*consdata != NULL);
2101
2102 nvars = (*consdata)->nvars;
2103 varssize = (*consdata)->varssize;
2104
2105 if( varssize > 0 )
2106 {
2107 int v;
2108
2109 /* release and free the rows */
2110 SCIP_CALL( consdataFreeRows(scip, consdata) );
2111
2112 /* release the linking constraints if they were generated */
2113 if( (*consdata)->linkingconss != NULL )
2114 {
2115 for( v = nvars-1; v >= 0; --v )
2116 {
2117 assert((*consdata)->linkingconss[v] != NULL );
2118 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2119 }
2120
2121 SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2122 }
2123
2124 /* free arrays */
2125 SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2126 SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2127 SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2128 SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2129 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2130 }
2131
2132 /* free memory */
2133 SCIPfreeBlockMemory(scip, consdata);
2134
2135 return SCIP_OKAY;
2136}
2137
2138/** prints cumulative constraint to file stream */
2139static
2141 SCIP* scip, /**< SCIP data structure */
2142 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2143 FILE* file /**< output file (or NULL for standard output) */
2144 )
2145{
2146 int v;
2147
2148 assert(consdata != NULL);
2149
2150 /* print coefficients */
2151 SCIPinfoMessage( scip, file, "cumulative(");
2152
2153 for( v = 0; v < consdata->nvars; ++v )
2154 {
2155 assert(consdata->vars[v] != NULL);
2156 if( v > 0 )
2157 SCIPinfoMessage(scip, file, ", ");
2158 SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2159 SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2160 consdata->durations[v], consdata->demands[v]);
2161 }
2162 SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2163}
2164
2165/** deletes coefficient at given position from constraint data */
2166static
2168 SCIP* scip, /**< SCIP data structure */
2169 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2170 SCIP_CONS* cons, /**< knapsack constraint */
2171 int pos /**< position of coefficient to delete */
2172 )
2173{
2174 SCIP_CONSHDLR* conshdlr;
2175 SCIP_CONSHDLRDATA* conshdlrdata;
2176
2177 assert(scip != NULL);
2178 assert(consdata != NULL);
2179 assert(cons != NULL);
2180 assert(SCIPconsIsTransformed(cons));
2181 assert(!SCIPinProbing(scip));
2182
2183 SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2184 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2185
2186 /* remove the rounding locks for the deleted variable */
2187 SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2188
2189 consdata->downlocks[pos] = FALSE;
2190 consdata->uplocks[pos] = FALSE;
2191
2192 if( consdata->linkingconss != NULL )
2193 {
2194 SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2195 }
2196
2197 /* get event handler */
2198 conshdlr = SCIPconsGetHdlr(cons);
2199 assert(conshdlr != NULL);
2200 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2201 assert(conshdlrdata != NULL);
2202 assert(conshdlrdata->eventhdlr != NULL);
2203
2204 /* drop events */
2205 SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2206
2207 SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2208 SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2209
2210 /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2211 * position
2212 */
2213 if( pos != consdata->nvars - 1 )
2214 {
2215 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2216 consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2217 consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2218 consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2219 consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2220
2221 if( consdata->linkingconss != NULL )
2222 {
2223 consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2224 }
2225 }
2226
2227 consdata->nvars--;
2228 consdata->validsignature = FALSE;
2229 consdata->normalized = FALSE;
2230
2231 return SCIP_OKAY;
2232}
2233
2234/** collect linking constraints for each integer variable */
2235static
2237 SCIP* scip, /**< SCIP data structure */
2238 SCIP_CONSDATA* consdata /**< pointer to consdata */
2239 )
2240{
2241 int nvars;
2242 int v;
2243
2244 assert(scip != NULL);
2245 assert(consdata != NULL);
2246
2247 nvars = consdata->nvars;
2248 assert(nvars > 0);
2249 assert(consdata->linkingconss == NULL);
2250
2251 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2252
2253 for( v = 0; v < nvars; ++v )
2254 {
2255 SCIP_CONS* cons;
2256 SCIP_VAR* var;
2257
2258 var = consdata->vars[v];
2259 assert(var != NULL);
2260
2261 SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2262
2263 /* create linking constraint if it does not exist yet */
2264 if( !SCIPexistsConsLinking(scip, var) )
2265 {
2266 char name[SCIP_MAXSTRLEN];
2267
2268 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2269
2270 /* creates and captures an linking constraint */
2271 SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2272 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2273 SCIP_CALL( SCIPaddCons(scip, cons) );
2274 consdata->linkingconss[v] = cons;
2275 }
2276 else
2277 {
2278 consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2279 SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2280 }
2281
2282 assert(SCIPexistsConsLinking(scip, var));
2283 assert(consdata->linkingconss[v] != NULL);
2284 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2285 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2286 }
2287
2288 return SCIP_OKAY;
2289}
2290
2291/**@} */
2292
2293
2294/**@name Check methods
2295 *
2296 * @{
2297 */
2298
2299/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2300 * given solution is satisfied
2301 */
2302static
2304 SCIP* scip, /**< SCIP data structure */
2305 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2306 int nvars, /**< number of variables (jobs) */
2307 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2308 int* durations, /**< array containing corresponding durations */
2309 int* demands, /**< array containing corresponding demands */
2310 int capacity, /**< available cumulative capacity */
2311 int hmin, /**< left bound of time axis to be considered (including hmin) */
2312 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2313 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2314 SCIP_CONS* cons, /**< constraint which is checked */
2315 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2316 )
2317{
2318 int* startsolvalues; /* stores when each job is starting */
2319 int* endsolvalues; /* stores when each job ends */
2320 int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2321 int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2322
2323 int freecapacity;
2324 int curtime; /* point in time which we are just checking */
2325 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2326 int j;
2327
2328 SCIP_Real absviol;
2329 SCIP_Real relviol;
2330
2331 assert(scip != NULL);
2332 assert(violated != NULL);
2333
2334 (*violated) = FALSE;
2335
2336 if( nvars == 0 )
2337 return SCIP_OKAY;
2338
2339 assert(vars != NULL);
2340 assert(demands != NULL);
2341 assert(durations != NULL);
2342
2343 /* compute time points where we have to check whether capacity constraint is infeasible or not */
2344 SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2345 SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2346 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2347 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2348
2349 /* assign variables, start and endpoints to arrays */
2350 for ( j = 0; j < nvars; ++j )
2351 {
2352 int solvalue;
2353
2354 /* the constraint of the cumulative constraint handler should be called after the integrality check */
2355 assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2356
2357 solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2358
2359 /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2360 * jobs which start before hmin to hmin
2361 */
2362 startsolvalues[j] = MAX(solvalue, hmin);
2363 startindices[j] = j;
2364
2365 endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2366 endindices[j] = j;
2367 }
2368
2369 /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2370 * corresponding indices in the same way)
2371 */
2372 SCIPsortIntInt(startsolvalues, startindices, nvars);
2373 SCIPsortIntInt(endsolvalues, endindices, nvars);
2374
2375 endindex = 0;
2376 freecapacity = capacity;
2377 absviol = 0.0;
2378 relviol = 0.0;
2379
2380 /* check each start point of a job whether the capacity is kept or not */
2381 for( j = 0; j < nvars; ++j )
2382 {
2383 /* only check intervals [hmin,hmax) */
2384 curtime = startsolvalues[j];
2385
2386 if( curtime >= hmax )
2387 break;
2388
2389 /* subtract all capacity needed up to this point */
2390 freecapacity -= demands[startindices[j]];
2391 while( j+1 < nvars && startsolvalues[j+1] == curtime )
2392 {
2393 j++;
2394 freecapacity -= demands[startindices[j]];
2395 }
2396
2397 /* free all capacity usages of jobs that are no longer running */
2398 while( endindex < nvars && curtime >= endsolvalues[endindex] )
2399 {
2400 freecapacity += demands[endindices[endindex]];
2401 ++endindex;
2402 }
2403 assert(freecapacity <= capacity);
2404
2405 /* update absolute and relative violation */
2406 if( absviol < (SCIP_Real) (-freecapacity) )
2407 {
2408 absviol = -freecapacity;
2409 relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2410 }
2411
2412 /* check freecapacity to be smaller than zero */
2413 if( freecapacity < 0 && curtime >= hmin )
2414 {
2415 SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2416 (*violated) = TRUE;
2417
2418 if( printreason )
2419 {
2420 int i;
2421
2422 /* first state the violated constraints */
2423 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2424
2425 /* second state the reason */
2427 ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2428 curtime, capacity, capacity - freecapacity);
2429
2430 for( i = 0; i <= j; ++i )
2431 {
2432 if( startsolvalues[i] + durations[startindices[i]] > curtime )
2433 {
2434 SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2435 SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2436 demands[startindices[i]]);
2437 }
2438 }
2439 }
2440 break;
2441 }
2442 } /*lint --e{850}*/
2443
2444 /* update constraint violation in solution */
2445 if( sol != NULL )
2446 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2447
2448 /* free all buffer arrays */
2449 SCIPfreeBufferArray(scip, &endindices);
2450 SCIPfreeBufferArray(scip, &startindices);
2451 SCIPfreeBufferArray(scip, &endsolvalues);
2452 SCIPfreeBufferArray(scip, &startsolvalues);
2453
2454 return SCIP_OKAY;
2455}
2456
2457/** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2458 * least zero or not. If not (*violated) is set to TRUE
2459 */
2460static
2462 SCIP* scip, /**< SCIP data structure */
2463 SCIP_CONS* cons, /**< constraint to be checked */
2464 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2465 SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2466 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2467 )
2468{
2469 SCIP_CONSDATA* consdata;
2470
2471 assert(scip != NULL);
2472 assert(cons != NULL);
2473 assert(violated != NULL);
2474
2475 SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2476
2477 consdata = SCIPconsGetData(cons);
2478 assert(consdata != NULL);
2479
2480 /* check the cumulative condition */
2481 SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2482 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2483 violated, cons, printreason) );
2484
2485 return SCIP_OKAY;
2486}
2487
2488/**@} */
2489
2490/**@name Conflict analysis
2491 *
2492 * @{
2493 */
2494
2495/** resolves the propagation of the core time algorithm */
2496static
2498 SCIP* scip, /**< SCIP data structure */
2499 int nvars, /**< number of start time variables (activities) */
2500 SCIP_VAR** vars, /**< array of start time variables */
2501 int* durations, /**< array of durations */
2502 int* demands, /**< array of demands */
2503 int capacity, /**< cumulative capacity */
2504 int hmin, /**< left bound of time axis to be considered (including hmin) */
2505 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2506 SCIP_VAR* infervar, /**< inference variable */
2507 int inferdemand, /**< demand of the inference variable */
2508 int inferpeak, /**< time point which causes the propagation */
2509 int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2510 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2511 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2512 int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2513 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2514 )
2515{
2516 SCIP_VAR* var;
2517 SCIP_Bool* reported;
2518 int duration;
2519 int maxlst;
2520 int minect;
2521 int ect;
2522 int lst;
2523 int j;
2524
2526
2527 SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2528 SCIPvarGetName(infervar), inferdemand, inferpeak);
2529 assert(nvars > 0);
2530
2531 /* adjusted capacity */
2532 capacity -= inferdemand;
2533 maxlst = INT_MIN;
2534 minect = INT_MAX;
2535
2536 SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2537 BMSclearMemoryArray(reported, nvars);
2538
2539 /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2540 * inference peak and those where the current conflict bounds provide a core at the inference peak
2541 */
2542 for( j = 0; j < nvars && capacity >= 0; ++j )
2543 {
2544 var = vars[j];
2545 assert(var != NULL);
2546
2547 /* skip inference variable */
2548 if( var == infervar )
2549 continue;
2550
2551 duration = durations[j];
2552 assert(duration > 0);
2553
2554 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2555 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2556 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2557 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2558 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2559
2560 SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2562 SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2563
2564 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2566
2567 /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2568 * that job without adding it the explanation
2569 */
2570 if( inferpeak < ect && lst <= inferpeak )
2571 {
2572 capacity -= demands[j];
2573 reported[j] = TRUE;
2574
2575 maxlst = MAX(maxlst, lst);
2576 minect = MIN(minect, ect);
2577 assert(maxlst < minect);
2578
2579 if( explanation != NULL )
2580 explanation[j] = TRUE;
2581
2582 continue;
2583 }
2584
2585 /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2586 * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2587 * not part of the conflict yet we get the global bounds back.
2588 */
2589 ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2591
2592 /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2593 * of that job without and collect the job as part of the explanation
2594 *
2595 * @note we do not need to reported that job to SCIP since the required bounds are already reported
2596 */
2597 if( inferpeak < ect && lst <= inferpeak )
2598 {
2599 capacity -= demands[j];
2600 reported[j] = TRUE;
2601
2602 maxlst = MAX(maxlst, lst);
2603 minect = MIN(minect, ect);
2604 assert(maxlst < minect);
2605
2606 if( explanation != NULL )
2607 explanation[j] = TRUE;
2608 }
2609 }
2610
2611 if( capacity >= 0 )
2612 {
2613 int* cands;
2614 int* canddemands;
2615 int ncands;
2616 int c;
2617
2618 SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2619 SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2620 ncands = 0;
2621
2622 /* collect all cores of the variables which lay in the considered time window except the inference variable */
2623 for( j = 0; j < nvars; ++j )
2624 {
2625 var = vars[j];
2626 assert(var != NULL);
2627
2628 /* skip inference variable */
2629 if( var == infervar || reported[j] )
2630 continue;
2631
2632 duration = durations[j];
2633 assert(duration > 0);
2634
2635 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2636 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2637 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2638 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2639 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2640
2641 /* collect local core information */
2642 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2643 lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2644
2645 SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2646 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2647 SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2648
2649 /* check if the inference peak is part of the core */
2650 if( inferpeak < ect && lst <= inferpeak )
2651 {
2652 cands[ncands] = j;
2653 canddemands[ncands] = demands[j];
2654 ncands++;
2655
2656 capacity -= demands[j];
2657 }
2658 }
2659
2660 /* sort candidates indices w.r.t. their demands */
2661 SCIPsortDownIntInt(canddemands, cands, ncands);
2662
2663 assert(capacity < 0);
2664 assert(ncands > 0);
2665
2666 /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2667 while( capacity + canddemands[ncands-1] < 0 )
2668 {
2669 ncands--;
2670 capacity += canddemands[ncands];
2671 assert(ncands > 0);
2672 }
2673
2674 /* compute the size (number of time steps) of the job cores */
2675 for( c = 0; c < ncands; ++c )
2676 {
2677 var = vars[cands[c]];
2678 assert(var != NULL);
2679
2680 duration = durations[cands[c]];
2681
2682 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2683 lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2684
2685 maxlst = MAX(maxlst, lst);
2686 minect = MIN(minect, ect);
2687 assert(maxlst < minect);
2688 }
2689
2690 SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2691 assert(inferpeak >= maxlst);
2692 assert(inferpeak < minect);
2693
2694 /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2695 if( relaxedpeak < inferpeak )
2696 {
2697 inferpeak = MAX(maxlst, relaxedpeak);
2698 }
2699 else if( relaxedpeak > inferpeak )
2700 {
2701 inferpeak = MIN(minect-1, relaxedpeak);
2702 }
2703 assert(inferpeak >= hmin);
2704 assert(inferpeak < hmax);
2705 assert(inferpeak >= maxlst);
2706 assert(inferpeak < minect);
2707
2708 /* post all necessary bound changes */
2709 for( c = 0; c < ncands; ++c )
2710 {
2711 var = vars[cands[c]];
2712 assert(var != NULL);
2713
2714 if( usebdwidening )
2715 {
2716 duration = durations[cands[c]];
2717
2718 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2719 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2720 }
2721 else
2722 {
2723 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2724 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2725 }
2726
2727 if( explanation != NULL )
2728 explanation[cands[c]] = TRUE;
2729 }
2730
2731 SCIPfreeBufferArray(scip, &canddemands);
2732 SCIPfreeBufferArray(scip, &cands);
2733 }
2734
2735 SCIPfreeBufferArray(scip, &reported);
2736
2737 if( provedpeak != NULL )
2738 *provedpeak = inferpeak;
2739
2740 return SCIP_OKAY;
2741}
2742
2743/** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2744static
2746 int begin, /**< begin of the times interval */
2747 int end, /**< end of time interval */
2748 int est, /**< earliest start time */
2749 int lst, /**< latest start time */
2750 int duration /**< duration of the job */
2751 )
2752{
2753 int left;
2754 int right;
2755 int ect;
2756 int lct;
2757
2758 ect = est + duration;
2759 lct = lst + duration;
2760
2761 /* check if job runs completely within [begin,end) */
2762 if( lct <= end && est >= begin )
2763 return duration;
2764
2765 assert(lst <= end && ect >= begin);
2766
2767 left = ect - begin;
2768 assert(left > 0);
2769
2770 right = end - lst;
2771 assert(right > 0);
2772
2773 return MIN3(left, right, end - begin);
2774}
2775
2776/** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2777 * reason
2778 *
2779 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2780 */
2781static
2783 SCIP* scip, /**< SCIP data structure */
2784 int nvars, /**< number of start time variables (activities) */
2785 SCIP_VAR** vars, /**< array of start time variables */
2786 int* durations, /**< array of durations */
2787 int* demands, /**< array of demands */
2788 int capacity, /**< capacity of the cumulative condition */
2789 int begin, /**< begin of the time window */
2790 int end, /**< end of the time window */
2791 SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2792 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2793 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2794 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2795 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2796 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2797 )
2798{
2799 int* locenergies;
2800 int* overlaps;
2801 int* idxs;
2802
2803 SCIP_Longint requiredenergy;
2804 int v;
2805
2806 SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2807 SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2808 SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2809
2810 /* energy which needs be explained */
2811 requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2812
2813 SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2814
2815 /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2816 * takes
2817 */
2818 for( v = 0; v < nvars; ++v )
2819 {
2820 SCIP_VAR* var;
2821 int glbenergy;
2822 int duration;
2823 int demand;
2824 int est;
2825 int lst;
2826
2827 var = vars[v];
2828 assert(var != NULL);
2829
2830 locenergies[v] = 0;
2831 overlaps[v] = 0;
2832 idxs[v] = v;
2833
2834 demand = demands[v];
2835 assert(demand > 0);
2836
2837 duration = durations[v];
2838 assert(duration > 0);
2839
2840 /* check if the variable equals the inference variable (the one which was propagated) */
2841 if( infervar == var )
2842 {
2843 int overlap;
2844 int right;
2845 int left;
2846
2847 assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2848
2849 SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2850 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2851 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2852
2853 /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2854 * which is necessary from the inference variable
2855 */
2856 if( boundtype == SCIP_BOUNDTYPE_UPPER )
2857 {
2858 int lct;
2859
2860 /* get the latest start time of the infer start time variable before the propagation took place */
2861 lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2862
2863 /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2864 * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2865 * scheduled w.r.t. its latest start time
2866 */
2867 assert(lst < end);
2868
2869 /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2870 * interval (before the propagation)
2871 */
2872 right = MIN3(end - lst, end - begin, duration);
2873
2874 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2875 assert(right > 0);
2876
2877 lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2878 assert(begin <= lct);
2879 assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2880
2881 /* compute the overlap of the job after the propagation but considering the relaxed bound */
2882 left = MIN(lct - begin + 1, end - begin);
2883 assert(left > 0);
2884
2885 /* compute the minimum overlap; */
2886 overlap = MIN(left, right);
2887 assert(overlap > 0);
2888 assert(overlap <= end - begin);
2889 assert(overlap <= duration);
2890
2891 if( usebdwidening )
2892 {
2893 assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2894 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2895 }
2896 else
2897 {
2898 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2899 }
2900 }
2901 else
2902 {
2903 int ect;
2904
2905 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2906
2907 /* get the earliest completion time of the infer start time variable before the propagation took place */
2908 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2909
2910 /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2911 * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2912 * the job is scheduled w.r.t. its earliest start time
2913 */
2914 assert(ect > begin);
2915
2916 /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2917 * interval (before the propagation)
2918 */
2919 left = MIN3(ect - begin, end - begin, duration);
2920
2921 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2922 assert(left > 0);
2923
2924 est = SCIPconvertRealToInt(scip, relaxedbd);
2925 assert(end >= est);
2926 assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
2927
2928 /* compute the overlap of the job after the propagation but considering the relaxed bound */
2929 right = MIN(end - est + 1, end - begin);
2930 assert(right > 0);
2931
2932 /* compute the minimum overlap */
2933 overlap = MIN(left, right);
2934 assert(overlap > 0);
2935 assert(overlap <= end - begin);
2936 assert(overlap <= duration);
2937
2938 if( usebdwidening )
2939 {
2940 assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
2941 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
2942 }
2943 else
2944 {
2945 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2946 }
2947 }
2948
2949 /* subtract the amount of energy which is available due to the overlap of the inference start time */
2950 requiredenergy -= (SCIP_Longint) overlap * demand;
2951
2952 if( explanation != NULL )
2953 explanation[v] = TRUE;
2954
2955 continue;
2956 }
2957
2958 /* global time points */
2961
2962 glbenergy = 0;
2963
2964 /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
2965 * time window
2966 */
2967 if( est + duration > begin && lst < end )
2968 {
2969 /* evaluated global contribution */
2970 glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
2971
2972 /* remove the globally available energy form the required energy */
2973 requiredenergy -= glbenergy;
2974
2975 if( explanation != NULL )
2976 explanation[v] = TRUE;
2977 }
2978
2979 /* local time points */
2980 est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2981 lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2982
2983 /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
2984 * time window
2985 */
2986 if( est + duration > begin && lst < end )
2987 {
2988 overlaps[v] = computeOverlap(begin, end, est, lst, duration);
2989
2990 /* evaluated additionally local energy contribution */
2991 locenergies[v] = overlaps[v] * demand - glbenergy;
2992 assert(locenergies[v] >= 0);
2993 }
2994 }
2995
2996 /* sort the variable contributions w.r.t. additional local energy contributions */
2997 SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
2998
2999 /* add local energy contributions until an overload is implied */
3000 for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3001 {
3002 SCIP_VAR* var;
3003 int duration;
3004 int overlap;
3005 int relaxlb;
3006 int relaxub;
3007 int idx;
3008
3009 idx = idxs[v];
3010 assert(idx >= 0 && idx < nvars);
3011
3012 var = vars[idx];
3013 assert(var != NULL);
3014 assert(var != infervar);
3015
3016 duration = durations[idx];
3017 assert(duration > 0);
3018
3019 overlap = overlaps[v];
3020 assert(overlap > 0);
3021
3022 requiredenergy -= locenergies[v];
3023
3024 if( requiredenergy < -1 )
3025 {
3026 int demand;
3027
3028 demand = demands[idx];
3029 assert(demand > 0);
3030
3031 overlap += (int)((requiredenergy + 1) / demand);
3032
3033#ifndef NDEBUG
3034 requiredenergy += locenergies[v];
3035 requiredenergy -= (SCIP_Longint) overlap * demand;
3036 assert(requiredenergy < 0);
3037#endif
3038 }
3039 assert(overlap > 0);
3040
3041 relaxlb = begin - duration + overlap;
3042 relaxub = end - overlap;
3043
3044 SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3045 SCIPvarGetName(var),
3049 relaxlb, relaxub, demands[idx], duration);
3050
3051 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3052 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3053
3054 if( explanation != NULL )
3055 explanation[idx] = TRUE;
3056 }
3057
3058 assert(requiredenergy < 0);
3059
3060 SCIPfreeBufferArray(scip, &idxs);
3061 SCIPfreeBufferArray(scip, &overlaps);
3062 SCIPfreeBufferArray(scip, &locenergies);
3063
3064 return SCIP_OKAY;
3065}
3066
3067/** resolve propagation w.r.t. the cumulative condition */
3068static
3070 SCIP* scip, /**< SCIP data structure */
3071 int nvars, /**< number of start time variables (activities) */
3072 SCIP_VAR** vars, /**< array of start time variables */
3073 int* durations, /**< array of durations */
3074 int* demands, /**< array of demands */
3075 int capacity, /**< cumulative capacity */
3076 int hmin, /**< left bound of time axis to be considered (including hmin) */
3077 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3078 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3079 INFERINFO inferinfo, /**< the user information */
3080 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3081 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3082 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3083 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3084 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3085 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3086 )
3087{
3088 switch( inferInfoGetProprule(inferinfo) )
3089 {
3091 {
3092 int inferdemand;
3093 int inferduration;
3094 int inferpos;
3095 int inferpeak;
3096 int relaxedpeak;
3097 int provedpeak;
3098
3099 /* get the position of the inferred variable in the vars array */
3100 inferpos = inferInfoGetData1(inferinfo);
3101 if( inferpos >= nvars || vars[inferpos] != infervar )
3102 {
3103 /* find inference variable in constraint */
3104 for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3105 {}
3106 }
3107 assert(inferpos < nvars);
3108 assert(vars[inferpos] == infervar);
3109
3110 inferdemand = demands[inferpos];
3111 inferduration = durations[inferpos];
3112
3113 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3114 {
3115 /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3116 * the inference variable
3117 */
3118 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3119
3120 SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3121 SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3122 SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3123
3124 /* get the inference peak that the time point which lead to the that propagtion */
3125 inferpeak = inferInfoGetData2(inferinfo);
3126 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3127 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3128 */
3129 assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3130 relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3131
3132 /* make sure that the relaxed peak is part of the effective horizon */
3133 relaxedpeak = MIN(relaxedpeak, hmax-1);
3134
3135 /* make sure that relaxed peak is not larger than the infer peak
3136 *
3137 * This can happen in case the variable is not an active variable!
3138 */
3139 relaxedpeak = MAX(relaxedpeak, inferpeak);
3140 assert(relaxedpeak >= inferpeak);
3141 assert(relaxedpeak >= hmin);
3142 }
3143 else
3144 {
3145 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3146
3147 SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3148 SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3149 SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3150
3151 /* get the time interval where the job could not be scheduled */
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(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3157 relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3158
3159 /* make sure that the relaxed peak is part of the effective horizon */
3160 relaxedpeak = MAX(relaxedpeak, hmin);
3161
3162 /* make sure that relaxed peak is not larger than the infer peak
3163 *
3164 * This can happen in case the variable is not an active variable!
3165 */
3166 relaxedpeak = MIN(relaxedpeak, inferpeak);
3167 assert(relaxedpeak < hmax);
3168 }
3169
3170 /* resolves the propagation of the core time algorithm */
3171 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3172 infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3173
3174 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3175 {
3176 if( usebdwidening )
3177 {
3178 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3179 }
3180 else
3181 {
3182 /* old upper bound of variable itself is part of the explanation */
3183 SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3184 }
3185 }
3186 else
3187 {
3188 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3189
3190 if( usebdwidening )
3191 {
3192 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3193 }
3194 else
3195 {
3196 /* old lower bound of variable itself is part of the explanation */
3197 SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3198 }
3199 }
3200
3201 if( explanation != NULL )
3202 explanation[inferpos] = TRUE;
3203
3204 break;
3205 }
3207 case PROPRULE_3_TTEF:
3208 {
3209 int begin;
3210 int end;
3211
3212 begin = inferInfoGetData1(inferinfo);
3213 end = inferInfoGetData2(inferinfo);
3214 assert(begin < end);
3215
3216 begin = MAX(begin, hmin);
3217 end = MIN(end, hmax);
3218
3219 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3220 begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3221
3222 break;
3223 }
3224
3225 case PROPRULE_0_INVALID:
3226 default:
3227 SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3228 SCIPABORT();
3229 return SCIP_INVALIDDATA; /*lint !e527*/
3230 }
3231
3232 (*result) = SCIP_SUCCESS;
3233
3234 return SCIP_OKAY;
3235}
3236
3237/**@} */
3238
3239
3240/**@name Enforcement methods
3241 *
3242 * @{
3243 */
3244
3245/** apply all fixings which are given by the alternative bounds */
3246static
3248 SCIP* scip, /**< SCIP data structure */
3249 SCIP_VAR** vars, /**< array of active variables */
3250 int nvars, /**< number of active variables */
3251 int* alternativelbs, /**< alternative lower bounds */
3252 int* alternativeubs, /**< alternative lower bounds */
3253 int* downlocks, /**< number of constraints with down lock participating by the computation */
3254 int* uplocks, /**< number of constraints with up lock participating by the computation */
3255 SCIP_Bool* branched /**< pointer to store if a branching was applied */
3256 )
3257{
3258 int v;
3259
3260 for( v = 0; v < nvars; ++v )
3261 {
3262 SCIP_VAR* var;
3263 SCIP_Real objval;
3264
3265 var = vars[v];
3266 assert(var != NULL);
3267
3268 objval = SCIPvarGetObj(var);
3269
3270 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3271 {
3272 int ub;
3273
3275
3276 if( alternativelbs[v] <= ub )
3277 {
3278 SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3279 (*branched) = TRUE;
3280
3281 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3282 SCIPvarGetLbLocal(var), alternativelbs[v]);
3283
3284 return SCIP_OKAY;
3285 }
3286 }
3287
3288 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3289 {
3290 int lb;
3291
3293
3294 if( alternativeubs[v] >= lb )
3295 {
3296 SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3297 (*branched) = TRUE;
3298
3299 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3300 alternativeubs[v], SCIPvarGetUbLocal(var));
3301
3302 return SCIP_OKAY;
3303 }
3304 }
3305 }
3306
3307 return SCIP_OKAY;
3308}
3309
3310/** remove the capacity requirments for all job which start at the curtime */
3311static
3313 SCIP_CONSDATA* consdata, /**< constraint data */
3314 int curtime, /**< current point in time */
3315 int* starttimes, /**< array of start times */
3316 int* startindices, /**< permutation with respect to the start times */
3317 int* freecapacity, /**< pointer to store the resulting free capacity */
3318 int* idx, /**< pointer to index in start time array */
3319 int nvars /**< number of vars in array of starttimes and startindices */
3320 )
3321{
3322#if defined SCIP_DEBUG && !defined NDEBUG
3323 int oldidx;
3324
3325 assert(idx != NULL);
3326 oldidx = *idx;
3327#else
3328 assert(idx != NULL);
3329#endif
3330
3331 assert(starttimes != NULL);
3332 assert(starttimes != NULL);
3333 assert(freecapacity != NULL);
3334 assert(starttimes[*idx] == curtime);
3335 assert(consdata->demands != NULL);
3336 assert(freecapacity != idx);
3337
3338 /* subtract all capacity needed up to this point */
3339 (*freecapacity) -= consdata->demands[startindices[*idx]];
3340
3341 while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3342 {
3343 ++(*idx);
3344 (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3345 assert(freecapacity != idx);
3346 }
3347#ifdef SCIP_DEBUG
3348 assert(oldidx <= *idx);
3349#endif
3350}
3351
3352/** add the capacity requirments for all job which end at the curtime */
3353static
3355 SCIP_CONSDATA* consdata, /**< constraint data */
3356 int curtime, /**< current point in time */
3357 int* endtimes, /**< array of end times */
3358 int* endindices, /**< permutation with rspect to the end times */
3359 int* freecapacity, /**< pointer to store the resulting free capacity */
3360 int* idx, /**< pointer to index in end time array */
3361 int nvars /**< number of vars in array of starttimes and startindices */
3362 )
3363{
3364#if defined SCIP_DEBUG && !defined NDEBUG
3365 int oldidx;
3366 oldidx = *idx;
3367#endif
3368
3369 /* free all capacity usages of jobs the are no longer running */
3370 while( endtimes[*idx] <= curtime && *idx < nvars)
3371 {
3372 (*freecapacity) += consdata->demands[endindices[*idx]];
3373 ++(*idx);
3374 }
3375
3376#ifdef SCIP_DEBUG
3377 assert(oldidx <= *idx);
3378#endif
3379}
3380
3381/** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3382static
3384 SCIP* scip, /**< SCIP data structure */
3385 SCIP_CONSDATA* consdata, /**< constraint handler data */
3386 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3387 int* timepoint /**< pointer to store the time point of the peak */
3388 )
3389{
3390 int* starttimes; /* stores when each job is starting */
3391 int* endtimes; /* stores when each job ends */
3392 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3393 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3394
3395 int nvars; /* number of activities for this constraint */
3396 int freecapacity; /* remaining capacity */
3397 int curtime; /* point in time which we are just checking */
3398 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3399
3400 int hmin;
3401 int hmax;
3402
3403 int j;
3404
3405 assert(consdata != NULL);
3406
3407 nvars = consdata->nvars;
3408 assert(nvars > 0);
3409
3410 *timepoint = consdata->hmax;
3411
3412 assert(consdata->vars != NULL);
3413
3414 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3415 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3416 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3417 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3418
3419 /* create event point arrays */
3420 createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3421 starttimes, endtimes, startindices, endindices);
3422
3423 endindex = 0;
3424 freecapacity = consdata->capacity;
3425 hmin = consdata->hmin;
3426 hmax = consdata->hmax;
3427
3428 /* check each startpoint of a job whether the capacity is kept or not */
3429 for( j = 0; j < nvars; ++j )
3430 {
3431 curtime = starttimes[j];
3432 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3433
3434 if( curtime >= hmax )
3435 break;
3436
3437 /* remove the capacity requirments for all job which start at the curtime */
3438 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3439
3440 /* add the capacity requirments for all job which end at the curtime */
3441 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3442
3443 assert(freecapacity <= consdata->capacity);
3444 assert(endindex <= nvars);
3445
3446 /* endindex - points to the next job which will finish */
3447 /* j - points to the last job that has been released */
3448
3449 /* if free capacity is smaller than zero, then add branching candidates */
3450 if( freecapacity < 0 && curtime >= hmin )
3451 {
3452 *timepoint = curtime;
3453 break;
3454 }
3455 } /*lint --e{850}*/
3456
3457 /* free all buffer arrays */
3458 SCIPfreeBufferArray(scip, &endindices);
3459 SCIPfreeBufferArray(scip, &startindices);
3460 SCIPfreeBufferArray(scip, &endtimes);
3461 SCIPfreeBufferArray(scip, &starttimes);
3462
3463 return SCIP_OKAY;
3464}
3465
3466/** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3467static
3469 SCIP* scip, /**< SCIP data structure */
3470 SCIP_CONS** conss, /**< constraints to be processed */
3471 int nconss, /**< number of constraints */
3472 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3473 int* nbranchcands /**< pointer to store the number of branching variables */
3474 )
3475{
3476 SCIP_HASHTABLE* collectedvars;
3477 int c;
3478
3479 assert(scip != NULL);
3480 assert(conss != NULL);
3481
3482 /* create a hash table */
3484 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3485
3486 assert(scip != NULL);
3487 assert(conss != NULL);
3488
3489 for( c = 0; c < nconss; ++c )
3490 {
3491 SCIP_CONS* cons;
3492 SCIP_CONSDATA* consdata;
3493
3494 int curtime;
3495 int j;
3496
3497 cons = conss[c];
3498 assert(cons != NULL);
3499
3500 if( !SCIPconsIsActive(cons) )
3501 continue;
3502
3503 consdata = SCIPconsGetData(cons);
3504 assert(consdata != NULL);
3505
3506 /* get point in time when capacity is exceeded */
3507 SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3508
3509 if( curtime < consdata->hmin || curtime >= consdata->hmax )
3510 continue;
3511
3512 /* report all variables that are running at that point in time */
3513 for( j = 0; j < consdata->nvars; ++j )
3514 {
3515 SCIP_VAR* var;
3516 int lb;
3517 int ub;
3518
3519 var = consdata->vars[j];
3520 assert(var != NULL);
3521
3522 /* check if the variable was already added */
3523 if( SCIPhashtableExists(collectedvars, (void*)var) )
3524 continue;
3525
3528
3529 if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3530 {
3531 SCIP_Real solval;
3532 SCIP_Real score;
3533
3534 solval = SCIPgetSolVal(scip, sol, var);
3535 score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3536
3537 SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3538 SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3539 (*nbranchcands)++;
3540
3541 SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3542 }
3543 }
3544 }
3545
3546 SCIPhashtableFree(&collectedvars);
3547
3548 SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3549
3550 return SCIP_OKAY;
3551}
3552
3553/** enforcement of an LP, pseudo, or relaxation solution */
3554static
3556 SCIP* scip, /**< SCIP data structure */
3557 SCIP_CONS** conss, /**< constraints to be processed */
3558 int nconss, /**< number of constraints */
3559 SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3560 SCIP_Bool branch, /**< should branching candidates be collected */
3561 SCIP_RESULT* result /**< pointer to store the result */
3562 )
3563{
3564 if( branch )
3565 {
3566 int nbranchcands;
3567
3568 nbranchcands = 0;
3569 SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3570
3571 if( nbranchcands > 0 )
3572 (*result) = SCIP_INFEASIBLE;
3573 }
3574 else
3575 {
3576 SCIP_Bool violated;
3577 int c;
3578
3579 violated = FALSE;
3580
3581 /* first check if a constraints is violated */
3582 for( c = 0; c < nconss && !violated; ++c )
3583 {
3584 SCIP_CONS* cons;
3585
3586 cons = conss[c];
3587 assert(cons != NULL);
3588
3589 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3590 }
3591
3592 if( violated )
3593 (*result) = SCIP_INFEASIBLE;
3594 }
3595
3596 return SCIP_OKAY;
3597}
3598
3599/**@} */
3600
3601/**@name Propagation
3602 *
3603 * @{
3604 */
3605
3606/** check if cumulative constraint is independently of all other constraints */
3607static
3609 SCIP_CONS* cons /**< cumulative constraint */
3610 )
3611{
3612 SCIP_CONSDATA* consdata;
3613 SCIP_VAR** vars;
3614 SCIP_Bool* downlocks;
3615 SCIP_Bool* uplocks;
3616 int nvars;
3617 int v;
3618
3619 consdata = SCIPconsGetData(cons);
3620 assert(consdata != NULL);
3621
3622 nvars = consdata->nvars;
3623 vars = consdata->vars;
3624 downlocks = consdata->downlocks;
3625 uplocks = consdata->uplocks;
3626
3627 /* check if the cumulative constraint has the only locks on the involved variables */
3628 for( v = 0; v < nvars; ++v )
3629 {
3630 SCIP_VAR* var;
3631
3632 var = vars[v];
3633 assert(var != NULL);
3634
3635 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3636 || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3637 return FALSE;
3638 }
3639
3640 return TRUE;
3641}
3642
3643/** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3644 * (dual reductions)
3645 */
3646static
3648 SCIP* scip, /**< SCIP data structure */
3649 SCIP_CONS* cons, /**< cumulative constraint */
3650 SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3651 int* nchgbds, /**< pointer to store the number changed variable bounds */
3652 int* nfixedvars, /**< pointer to count number of fixings */
3653 int* ndelconss, /**< pointer to count number of deleted constraints */
3654 SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3655 SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3656 )
3657{
3658 SCIP_CONSDATA* consdata;
3659 SCIP_VAR** vars;
3660 SCIP_Real* objvals;
3661 SCIP_Real* lbs;
3662 SCIP_Real* ubs;
3663 SCIP_Real timelimit;
3664 SCIP_Real memorylimit;
3665 SCIP_Bool solved;
3666 SCIP_Bool error;
3667
3668 int ncheckconss;
3669 int nvars;
3670 int v;
3671
3672 assert(scip != NULL);
3673 assert(!SCIPconsIsModifiable(cons));
3674 assert(SCIPgetNConss(scip) > 0);
3675
3676 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3677 * would/could end in an implication which can lead to cutoff of the/all optimal solution
3678 */
3680 return SCIP_OKAY;
3681
3682 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3683 * use the locks to decide for a dual reduction using this constraint;
3684 */
3685 if( !SCIPconsIsChecked(cons) )
3686 return SCIP_OKAY;
3687
3688 ncheckconss = SCIPgetNCheckConss(scip);
3689
3690 /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3691 * presolved problem do nothing execpt to change the parameter settings
3692 */
3693 if( ncheckconss == 1 )
3694 {
3695 /* shrink the minimal maximum value for the conflict length */
3696 SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3697
3698 /* use only first unique implication point */
3699 SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3700
3701 /* do not use reconversion conflicts */
3702 SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3703
3704 /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3705 SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3706
3707 /* increase the number of conflicts which induce a restart */
3708 SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3709
3710 /* weight the variable which made into a conflict */
3711 SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3712
3713 /* do not check pseudo solution (for performance reasons) */
3714 SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3715
3716 /* use value based history to detect a reasonable branching point */
3717 SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3718
3719 /* turn of LP relaxation */
3720 SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3721
3722 /* prefer the down branch in case the value based history does not suggest something */
3723 SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3724
3725 /* accept any bound change */
3726 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3727
3728 /* allow for at most 10 restart, after that the value based history should be reliable */
3729 SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3730
3731 /* set priority for depth first search to highest possible value */
3732 SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3733
3734 return SCIP_OKAY;
3735 }
3736
3737 consdata = SCIPconsGetData(cons);
3738 assert(consdata != NULL);
3739
3740 /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3741 * fail on the first place
3742 */
3743 if( consdata->triedsolving )
3744 return SCIP_OKAY;
3745
3746 /* check if constraint is independently */
3747 if( !isConsIndependently(cons) )
3748 return SCIP_OKAY;
3749
3750 /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3751 * constraint is deleted; otherwise, we want to ensure that we do not try that again
3752 */
3753 consdata->triedsolving = TRUE;
3754
3755 SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3758
3759 nvars = consdata->nvars;
3760 vars = consdata->vars;
3761
3762 SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3763 SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3764 SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3765
3766 for( v = 0; v < nvars; ++v )
3767 {
3768 SCIP_VAR* var;
3769
3770 /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3771 * array
3772 */
3773 var = vars[v];
3774 assert(var != NULL);
3775
3776 lbs[v] = SCIPvarGetLbLocal(var);
3777 ubs[v] = SCIPvarGetUbLocal(var);
3778
3779 objvals[v] = SCIPvarGetObj(var);
3780 }
3781
3782 /* check whether there is enough time and memory left */
3783 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3784 if( !SCIPisInfinity(scip, timelimit) )
3785 timelimit -= SCIPgetSolvingTime(scip);
3786 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3787
3788 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3789 if( !SCIPisInfinity(scip, memorylimit) )
3790 {
3791 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3792 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3793 }
3794
3795 /* solve the cumulative condition separately */
3796 SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3797 consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3798
3799 if( !(*cutoff) && !(*unbounded) && !error )
3800 {
3801 SCIP_Bool infeasible;
3802 SCIP_Bool tightened;
3803 SCIP_Bool allfixed;
3804
3805 allfixed = TRUE;
3806
3807 for( v = 0; v < nvars; ++v )
3808 {
3809 /* check if variable is fixed */
3810 if( lbs[v] + 0.5 > ubs[v] )
3811 {
3812 SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3813 assert(!infeasible);
3814
3815 if( tightened )
3816 {
3817 (*nfixedvars)++;
3818 consdata->triedsolving = FALSE;
3819 }
3820 }
3821 else
3822 {
3823 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3824 assert(!infeasible);
3825
3826 if( tightened )
3827 {
3828 (*nchgbds)++;
3829 consdata->triedsolving = FALSE;
3830 }
3831
3832 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3833 assert(!infeasible);
3834
3835 if( tightened )
3836 {
3837 (*nchgbds)++;
3838 consdata->triedsolving = FALSE;
3839 }
3840
3841 allfixed = FALSE;
3842 }
3843 }
3844
3845 /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3846 if( allfixed )
3847 {
3849 (*ndelconss)++;
3850 }
3851 }
3852
3853 SCIPfreeBufferArray(scip, &objvals);
3856
3857 return SCIP_OKAY;
3858}
3859
3860/** start conflict analysis to analysis the core insertion which is infeasible */
3861static
3863 SCIP* scip, /**< SCIP data structure */
3864 int nvars, /**< number of start time variables (activities) */
3865 SCIP_VAR** vars, /**< array of start time variables */
3866 int* durations, /**< array of durations */
3867 int* demands, /**< array of demands */
3868 int capacity, /**< cumulative capacity */
3869 int hmin, /**< left bound of time axis to be considered (including hmin) */
3870 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3871 SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3872 int inferduration, /**< duration of the start time variable */
3873 int inferdemand, /**< demand of the start time variable */
3874 int inferpeak, /**< profile preak which causes the infeasibilty */
3875 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3876 SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3877 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3878 )
3879{
3880 SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3881 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3882 SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3883
3884 /* initialize conflict analysis if conflict analysis is applicable */
3886 {
3888
3889 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3890 infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3891
3892 SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3893
3894 /* add both bound of the inference variable since these biuld the core which we could not inserted */
3895 if( usebdwidening )
3896 {
3897 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3898 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3899 }
3900 else
3901 {
3902 SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3903 SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3904 }
3905
3906 *initialized = TRUE;
3907 }
3908
3909 return SCIP_OKAY;
3910}
3911
3912/** We are using the core resource profile which contains all core except the one of the start time variable which we
3913 * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3914 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3915 * analysis
3916 */
3917static
3919 SCIP* scip, /**< SCIP data structure */
3920 int nvars, /**< number of start time variables (activities) */
3921 SCIP_VAR** vars, /**< array of start time variables */
3922 int* durations, /**< array of durations */
3923 int* demands, /**< array of demands */
3924 int capacity, /**< cumulative capacity */
3925 int hmin, /**< left bound of time axis to be considered (including hmin) */
3926 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3927 SCIP_CONS* cons, /**< constraint which is propagated */
3928 SCIP_PROFILE* profile, /**< resource profile */
3929 int idx, /**< position of the variable to propagate */
3930 int* nchgbds, /**< pointer to store the number of bound changes */
3931 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3932 SCIP_Bool* initialized, /**< was conflict analysis initialized */
3933 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3934 SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
3935 )
3936{
3937 SCIP_VAR* var;
3938 int ntimepoints;
3939 int duration;
3940 int demand;
3941 int peak;
3942 int newlb;
3943 int est;
3944 int lst;
3945 int pos;
3946
3947 var = vars[idx];
3948 assert(var != NULL);
3949
3950 duration = durations[idx];
3951 assert(duration > 0);
3952
3953 demand = demands[idx];
3954 assert(demand > 0);
3955
3958 ntimepoints = SCIPprofileGetNTimepoints(profile);
3959
3960 /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
3961 * load which we have at the earliest start time (lower bound)
3962 */
3963 (void) SCIPprofileFindLeft(profile, est, &pos);
3964
3965 SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
3966
3967 /* we now trying to move the earliest start time in steps of at most "duration" length */
3968 do
3969 {
3970 INFERINFO inferinfo;
3971 SCIP_Bool tightened;
3972 int ect;
3973
3974#ifndef NDEBUG
3975 {
3976 /* in debug mode we check that we adjust the search position correctly */
3977 int tmppos;
3978
3979 (void)SCIPprofileFindLeft(profile, est, &tmppos);
3980 assert(pos == tmppos);
3981 }
3982#endif
3983 ect = est + duration;
3984 peak = -1;
3985
3986 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
3987 * want a peak which is closest to the earliest completion time
3988 */
3989 do
3990 {
3991 /* check if the profile load conflicts with the demand of the start time variable */
3992 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
3993 peak = pos;
3994
3995 pos++;
3996 }
3997 while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
3998
3999 /* if we found no peak that means current the job could be scheduled at its earliest start time without
4000 * conflicting to the core resource profile
4001 */
4002 /* coverity[check_after_sink] */
4003 if( peak == -1 )
4004 break;
4005
4006 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4007 * profile. That means we have to move it to the next time point in the resource profile but at most to the
4008 * earliest completion time (the remaining move will done in the next loop)
4009 */
4010 newlb = SCIPprofileGetTime(profile, peak+1);
4011 newlb = MIN(newlb, ect);
4012
4013 /* if the earliest start time is greater than the lst we detected an infeasibilty */
4014 if( newlb > lst )
4015 {
4016 SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4017
4018 /* use conflict analysis to analysis the core insertion which was infeasible */
4019 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4020 var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4021
4022 if( explanation != NULL )
4023 explanation[idx] = TRUE;
4024
4025 *infeasible = TRUE;
4026
4027 break;
4028 }
4029
4030 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4031 * bound change
4032 */
4033 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4034
4035 /* perform the bound lower bound change */
4036 if( inferInfoIsValid(inferinfo) )
4037 {
4038 SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4039 }
4040 else
4041 {
4042 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4043 }
4044 assert(tightened);
4045 assert(!(*infeasible));
4046
4047 SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4048 (*nchgbds)++;
4049
4050 /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4052
4053 /* adjust the earliest start time
4054 *
4055 * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4056 * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4057 * involved.
4058 */
4060 assert(est >= newlb);
4061
4062 /* adjust the search position for the resource profile for the next step */
4063 if( est == SCIPprofileGetTime(profile, peak+1) )
4064 pos = peak + 1;
4065 else
4066 pos = peak;
4067 }
4068 while( est < lst );
4069
4070 return SCIP_OKAY;
4071}
4072
4073/** We are using the core resource profile which contains all core except the one of the start time variable which we
4074 * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4075 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4076 * analysis
4077 */
4078static
4080 SCIP* scip, /**< SCIP data structure */
4081 SCIP_VAR* var, /**< start time variable to propagate */
4082 int duration, /**< duration of the job */
4083 int demand, /**< demand of the job */
4084 int capacity, /**< cumulative capacity */
4085 SCIP_CONS* cons, /**< constraint which is propagated */
4086 SCIP_PROFILE* profile, /**< resource profile */
4087 int idx, /**< position of the variable to propagate */
4088 int* nchgbds /**< pointer to store the number of bound changes */
4089 )
4090{
4091 int ntimepoints;
4092 int newub;
4093 int peak;
4094 int pos;
4095 int est;
4096 int lst;
4097 int lct;
4098
4099 assert(var != NULL);
4100 assert(duration > 0);
4101 assert(demand > 0);
4102
4105
4106 /* in case the start time variable is fixed do nothing */
4107 if( est == lst )
4108 return SCIP_OKAY;
4109
4110 ntimepoints = SCIPprofileGetNTimepoints(profile);
4111
4112 lct = lst + duration;
4113
4114 /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4115 * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4116 * position gives us the load which we have at the latest completion time minus one
4117 */
4118 (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4119
4120 SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4122
4123 if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4124 return SCIP_OKAY;
4125
4126 /* we now trying to move the latest start time in steps of at most "duration" length */
4127 do
4128 {
4129 INFERINFO inferinfo;
4130 SCIP_Bool tightened;
4131 SCIP_Bool infeasible;
4132
4133 peak = -1;
4134
4135#ifndef NDEBUG
4136 {
4137 /* in debug mode we check that we adjust the search position correctly */
4138 int tmppos;
4139
4140 (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4141 assert(pos == tmppos);
4142 }
4143#endif
4144
4145 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4146 * want a peak which is closest to the latest start time
4147 */
4148 do
4149 {
4150 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4151 peak = pos;
4152
4153 pos--;
4154 }
4155 while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4156
4157 /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4158 * to the core resource profile
4159 */
4160 /* coverity[check_after_sink] */
4161 if( peak == -1 )
4162 break;
4163
4164 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4165 * profile. That means the job has be done until that point. Hence that gives us the latest completion
4166 * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4167 * doing in the next loop)
4168 */
4169 newub = SCIPprofileGetTime(profile, peak);
4170 newub = MAX(newub, lst) - duration;
4171 assert(newub >= est);
4172
4173 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4174 * bound change
4175 */
4176 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4177
4178 /* perform the bound upper bound change */
4179 if( inferInfoIsValid(inferinfo) )
4180 {
4181 SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4182 }
4183 else
4184 {
4185 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4186 }
4187 assert(tightened);
4188 assert(!infeasible);
4189
4190 SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4191 (*nchgbds)++;
4192
4193 /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4195
4196 /* adjust the latest start and completion time
4197 *
4198 * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4199 * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4200 * involved.
4201 */
4203 assert(lst <= newub);
4204 lct = lst + duration;
4205
4206 /* adjust the search position for the resource profile for the next step */
4207 if( SCIPprofileGetTime(profile, peak) == lct )
4208 pos = peak - 1;
4209 else
4210 pos = peak;
4211 }
4212 while( est < lst );
4213
4214 return SCIP_OKAY;
4215}
4216
4217/** compute for the different earliest start and latest completion time the core energy of the corresponding time
4218 * points
4219 */
4220static
4222 SCIP_PROFILE* profile, /**< core profile */
4223 int nvars, /**< number of start time variables (activities) */
4224 int* ests, /**< array of sorted earliest start times */
4225 int* lcts, /**< array of sorted latest completion times */
4226 int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4227 int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4228 )
4229{
4230 int ntimepoints;
4231 int energy;
4232 int t;
4233 int v;
4234
4235 ntimepoints = SCIPprofileGetNTimepoints(profile);
4236 t = ntimepoints - 1;
4237 energy = 0;
4238
4239 /* compute core energy after the earliest start time of each job */
4240 for( v = nvars-1; v >= 0; --v )
4241 {
4242 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4243 {
4244 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4245 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4246 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4247 t--;
4248 }
4249 assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4250
4251 /* maybe ests[j] is in-between two timepoints */
4252 if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4253 {
4254 assert(t > 0);
4255 coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4256 }
4257 else
4258 coreEnergyAfterEst[v] = energy;
4259 }
4260
4261 t = ntimepoints - 1;
4262 energy = 0;
4263
4264 /* compute core energy after the latest completion time of each job */
4265 for( v = nvars-1; v >= 0; --v )
4266 {
4267 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4268 {
4269 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4270 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4271 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4272 t--;
4273 }
4274 assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4275
4276 /* maybe lcts[j] is in-between two timepoints */
4277 if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4278 {
4279 assert(t > 0);
4280 coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4281 }
4282 else
4283 coreEnergyAfterLct[v] = energy;
4284 }
4285}
4286
4287/** collect earliest start times, latest completion time, and free energy contributions */
4288static
4290 SCIP* scip, /**< SCIP data structure */
4291 int nvars, /**< number of start time variables (activities) */
4292 SCIP_VAR** vars, /**< array of start time variables */
4293 int* durations, /**< array of durations */
4294 int* demands, /**< array of demands */
4295 int hmin, /**< left bound of time axis to be considered (including hmin) */
4296 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4297 int* permests, /**< array to store the variable positions */
4298 int* ests, /**< array to store earliest start times */
4299 int* permlcts, /**< array to store the variable positions */
4300 int* lcts, /**< array to store latest completion times */
4301 int* ects, /**< array to store earliest completion times of the flexible part of the job */
4302 int* lsts, /**< array to store latest start times of the flexible part of the job */
4303 int* flexenergies /**< array to store the flexible energies of each job */
4304 )
4305{
4306 int v;
4307
4308 for( v = 0; v < nvars; ++ v)
4309 {
4310 int duration;
4311 int leftadjust;
4312 int rightadjust;
4313 int core;
4314 int est;
4315 int lct;
4316 int ect;
4317 int lst;
4318
4319 duration = durations[v];
4320 assert(duration > 0);
4321
4324 ect = est + duration;
4325 lct = lst + duration;
4326
4327 ests[v] = est;
4328 lcts[v] = lct;
4329 permests[v] = v;
4330 permlcts[v] = v;
4331
4332 /* compute core time window which lies within the effective horizon */
4333 core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4334
4335 /* compute the number of time steps the job could run before the effective horizon */
4336 leftadjust = MAX(0, hmin - est);
4337
4338 /* compute the number of time steps the job could run after the effective horizon */
4339 rightadjust = MAX(0, lct - hmax);
4340
4341 /* compute for each job the energy which is flexible; meaning not part of the core */
4342 flexenergies[v] = duration - leftadjust - rightadjust - core;
4343 flexenergies[v] = MAX(0, flexenergies[v]);
4344 flexenergies[v] *= demands[v];
4345 assert(flexenergies[v] >= 0);
4346
4347 /* the earliest completion time of the flexible energy */
4348 ects[v] = MIN(ect, lst);
4349
4350 /* the latest start time of the flexible energy */
4351 lsts[v] = MAX(ect, lst);
4352 }
4353}
4354
4355/** try to tighten the lower bound of the given variable */
4356static
4358 SCIP* scip, /**< SCIP data structure */
4359 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4360 int nvars, /**< number of start time variables (activities) */
4361 SCIP_VAR** vars, /**< array of start time variables */
4362 int* durations, /**< array of durations */
4363 int* demands, /**< array of demands */
4364 int capacity, /**< cumulative capacity */
4365 int hmin, /**< left bound of time axis to be considered (including hmin) */
4366 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4367 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4368 int duration, /**< duration of the job */
4369 int demand, /**< demand of the job */
4370 int est, /**< earliest start time of the job */
4371 int ect, /**< earliest completion time of the flexible part of the job */
4372 int lct, /**< latest completion time of the job */
4373 int begin, /**< begin of the time window under investigation */
4374 int end, /**< end of the time window under investigation */
4375 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4376 int* bestlb, /**< pointer to strope the best lower bound change */
4377 int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4378 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4379 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4380 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4381 )
4382{
4383 int newlb;
4384
4385 assert(begin >= hmin);
4386 assert(end <= hmax);
4387
4388 /* check if the time-table edge-finding should infer bounds */
4389 if( !conshdlrdata->ttefinfer )
4390 return SCIP_OKAY;
4391
4392 /* if the job can be processed completely before or after the time window, nothing can be tightened */
4393 if( est >= end || ect <= begin )
4394 return SCIP_OKAY;
4395
4396 /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4397 * skip since the overload check will do the job
4398 */
4399 if( est >= begin && ect <= end )
4400 return SCIP_OKAY;
4401
4402 /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4403 * earliest start time
4404 */
4405 if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4406 return SCIP_OKAY;
4407
4408 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4409 * present; therefore, we need to add the core;
4410 *
4411 * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4412 * compute the earliest completion time of the (whole) job
4413 */
4414 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4415
4416 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4417 *
4418 * @note we can round down the compute duration w.r.t. the available energy
4419 */
4420 newlb = end - (int) (energy / demand);
4421
4422 /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4423 * bound (latest start time); meaning it is not possible to schedule the job
4424 */
4425 if( newlb > lct - duration )
4426 {
4427 /* initialize conflict analysis if conflict analysis is applicable */
4429 {
4430 SCIP_Real relaxedbd;
4431
4432 assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4433
4434 /* it is enough to overshoot the upper bound of the variable by one */
4435 relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4436
4437 /* initialize conflict analysis */
4439
4440 /* added to upper bound (which was overcut be new lower bound) of the variable */
4442
4443 /* analyze the infeasible */
4444 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4445 begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4446
4447 (*initialized) = TRUE;
4448 }
4449
4450 (*cutoff) = TRUE;
4451 }
4452 else if( newlb > (*bestlb) )
4453 {
4454 INFERINFO inferinfo;
4455
4456 assert(newlb > begin);
4457
4458 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4459
4460 /* construct inference information */
4461 (*inferinfos) = inferInfoToInt(inferinfo);
4462 (*bestlb) = newlb;
4463 }
4464
4465 return SCIP_OKAY;
4466}
4467
4468/** try to tighten the upper bound of the given variable */
4469static
4471 SCIP* scip, /**< SCIP data structure */
4472 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4473 int nvars, /**< number of start time variables (activities) */
4474 SCIP_VAR** vars, /**< array of start time variables */
4475 int* durations, /**< array of durations */
4476 int* demands, /**< array of demands */
4477 int capacity, /**< cumulative capacity */
4478 int hmin, /**< left bound of time axis to be considered (including hmin) */
4479 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4480 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4481 int duration, /**< duration of the job */
4482 int demand, /**< demand of the job */
4483 int est, /**< earliest start time of the job */
4484 int lst, /**< latest start time of the flexible part of the job */
4485 int lct, /**< latest completion time of the job */
4486 int begin, /**< begin of the time window under investigation */
4487 int end, /**< end of the time window under investigation */
4488 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4489 int* bestub, /**< pointer to strope the best upper bound change */
4490 int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4491 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4492 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4493 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4494 )
4495{
4496 int newub;
4497
4498 assert(begin >= hmin);
4499 assert(end <= hmax);
4500 assert(est < begin);
4501
4502 /* check if the time-table edge-finding should infer bounds */
4503 if( !conshdlrdata->ttefinfer )
4504 return SCIP_OKAY;
4505
4506 /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4507 if( lst >= end || lct <= begin )
4508 return SCIP_OKAY;
4509
4510 /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4511 * skip since the overload check will do the job
4512 */
4513 if( lst >= begin && lct <= end )
4514 return SCIP_OKAY;
4515
4516 /* check if the available energy in the time window is to small to handle the flexible part of the job */
4517 if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4518 return SCIP_OKAY;
4519
4520 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4521 * present; therefore, we need to add the core;
4522 *
4523 * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4524 * latest start of the (whole) job
4525 */
4526 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4527 assert(energy >= 0);
4528
4529 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4530 *
4531 * @note we can round down the compute duration w.r.t. the available energy
4532 */
4533 assert(demand > 0);
4534 newub = begin - duration + (int) (energy / demand);
4535
4536 /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4537 * bound (earliest start time); meaning it is not possible to schedule the job
4538 */
4539 if( newub < est )
4540 {
4541 /* initialize conflict analysis if conflict analysis is applicable */
4543 {
4544 SCIP_Real relaxedbd;
4545
4546 assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4547
4548 /* it is enough to undershoot the lower bound of the variable by one */
4549 relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4550
4551 /* initialize conflict analysis */
4553
4554 /* added to lower bound (which was undercut be new upper bound) of the variable */
4556
4557 /* analyze the infeasible */
4558 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4559 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4560
4561 (*initialized) = TRUE;
4562 }
4563
4564 (*cutoff) = TRUE;
4565 }
4566 else if( newub < (*bestub) )
4567 {
4568 INFERINFO inferinfo;
4569
4570 assert(newub < begin);
4571
4572 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4573
4574 /* construct inference information */
4575 (*inferinfos) = inferInfoToInt(inferinfo);
4576 (*bestub) = newub;
4577 }
4578
4579 return SCIP_OKAY;
4580}
4581
4582/** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4583static
4585 SCIP* scip, /**< SCIP data structure */
4586 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4587 int nvars, /**< number of start time variables (activities) */
4588 SCIP_VAR** vars, /**< array of start time variables */
4589 int* durations, /**< array of durations */
4590 int* demands, /**< array of demands */
4591 int capacity, /**< cumulative capacity */
4592 int hmin, /**< left bound of time axis to be considered (including hmin) */
4593 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4594 int* newlbs, /**< array to buffer new lower bounds */
4595 int* newubs, /**< array to buffer new upper bounds */
4596 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4597 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4598 int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4599 int* flexenergies, /**< array of flexible energies in the same order as the variables */
4600 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4601 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4602 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4603 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4604 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4605 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4606 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4607 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4608 )
4609{
4610 int coreEnergyAfterEnd;
4611 SCIP_Longint maxavailable;
4612 SCIP_Longint minavailable;
4613 SCIP_Longint totalenergy;
4614 int nests;
4615 int est;
4616 int lct;
4617 int start;
4618 int end;
4619 int v;
4620
4621 est = INT_MAX;
4622 lct = INT_MIN;
4623
4624 /* compute earliest start and latest completion time of all jobs */
4625 for( v = 0; v < nvars; ++v )
4626 {
4627 start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4628 end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4629
4630 est = MIN(est, start);
4631 lct = MAX(lct, end);
4632 }
4633
4634 /* adjust the effective time horizon */
4635 hmin = MAX(hmin, est);
4636 hmax = MIN(hmax, lct);
4637
4638 end = hmax + 1;
4639 coreEnergyAfterEnd = -1;
4640
4641 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4642 minavailable = maxavailable;
4643 totalenergy = computeTotalEnergy(durations, demands, nvars);
4644
4645 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4646 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4647 return SCIP_OKAY;
4648
4649 nests = nvars;
4650
4651 /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4652 * times define the end of the time interval under investigation
4653 */
4654 for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4655 {
4656 int flexenergy;
4657 int minbegin;
4658 int lbenergy;
4659 int lbcand;
4660 int i;
4661
4662 lct = lcts[v];
4663
4664 /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4665 * infinity capacity is available; hence we skip that
4666 */
4667 if( lct > hmax )
4668 continue;
4669
4670 /* if the latest completion time is smaller then hmin we have to stop */
4671 if( lct <= hmin )
4672 {
4673 assert(v == 0 || lcts[v-1] <= lcts[v]);
4674 break;
4675 }
4676
4677 /* if the latest completion time equals to previous end time, we can continue since this particular interval
4678 * induced by end was just analyzed
4679 */
4680 if( lct == end )
4681 continue;
4682
4683 assert(lct < end);
4684
4685 /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4686 * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4687 * free energy; if so it means that in the next iterate the free-energy cannot be negative
4688 */
4689 if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4690 {
4691 SCIP_Longint freeenergy;
4692
4693 assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4694 assert(coreEnergyAfterEnd >= 0);
4695
4696 /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4697 freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4698
4699 if( freeenergy <= minavailable )
4700 {
4701 SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4702 continue;
4703 }
4704 }
4705
4706 SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4707
4708 end = lct;
4709 coreEnergyAfterEnd = coreEnergyAfterLct[v];
4710
4711 flexenergy = 0;
4712 minavailable = maxavailable;
4713 minbegin = hmax;
4714 lbcand = -1;
4715 lbenergy = 0;
4716
4717 /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4718 * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4719 * wider
4720 */
4721 for( i = nests-1; i >= 0; --i )
4722 {
4723 SCIP_VAR* var;
4724 SCIP_Longint freeenergy;
4725 int duration;
4726 int demand;
4727 int begin;
4728 int idx;
4729 int lst;
4730
4731 idx = perm[i];
4732 assert(idx >= 0);
4733 assert(idx < nvars);
4734 assert(!(*cutoff));
4735
4736 /* the earliest start time of the job */
4737 est = ests[i];
4738
4739 /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4740 * latest completion times (which define end) are scant in non-increasing order
4741 */
4742 if( end <= est )
4743 {
4744 nests--;
4745 continue;
4746 }
4747
4748 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4749 * current ending time
4750 */
4751 if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4752 break;
4753
4754 var = vars[idx];
4755 assert(var != NULL);
4756
4757 duration = durations[idx];
4758 assert(duration > 0);
4759
4760 demand = demands[idx];
4761 assert(demand > 0);
4762
4763 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4764
4765 /* the latest start time of the free part of the job */
4766 lst = lsts[idx];
4767
4768 /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4769 * investigation; hence the overload check will do the the job
4770 */
4771 assert(est <= minbegin);
4772 if( minavailable < maxavailable && est < minbegin )
4773 {
4774 assert(!(*cutoff));
4775
4776 /* try to tighten the upper bound */
4777 SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4778 var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4779 initialized, explanation, cutoff) );
4780
4781 if( *cutoff )
4782 break;
4783 }
4784
4785 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4786 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4787
4788 begin = est;
4789 assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4790
4791 /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4792 * free energy
4793 */
4794 if( begin < hmin )
4795 break;
4796
4797 /* compute the contribution to the flexible energy */
4798 if( lct <= end )
4799 {
4800 /* if the jobs has to finish before the end, all the energy has to be scheduled */
4801 assert(lst >= begin);
4802 assert(flexenergies[idx] >= 0);
4803 flexenergy += flexenergies[idx];
4804 }
4805 else
4806 {
4807 /* the job partly overlaps with the end */
4808 int candenergy;
4809 int energy;
4810
4811 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4812 * w.r.t. latest start time
4813 *
4814 * @note we need to be aware of the effective horizon
4815 */
4816 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4817 assert(end - lst < duration);
4818 assert(energy >= 0);
4819
4820 /* adjust the flexible energy of the time interval */
4821 flexenergy += energy;
4822
4823 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4824 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4825 assert(candenergy >= 0);
4826
4827 /* check if we found a better candidate */
4828 if( candenergy > lbenergy )
4829 {
4830 lbenergy = candenergy;
4831 lbcand = idx;
4832 }
4833 }
4834
4835 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4836 assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4837
4838 /* compute the energy which is not used yet */
4839 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4840
4841 /* check overload */
4842 if( freeenergy < 0 )
4843 {
4844 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4845
4846 /* initialize conflict analysis if conflict analysis is applicable */
4848 {
4849 /* analyze infeasibilty */
4851
4852 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4854 conshdlrdata->usebdwidening, explanation) );
4855
4856 (*initialized) = TRUE;
4857 }
4858
4859 (*cutoff) = TRUE;
4860
4861 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4863
4864 break;
4865 }
4866
4867 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4868 if( lbenergy > 0 && freeenergy < lbenergy )
4869 {
4870 SCIP_Longint energy;
4871 int newlb;
4872 int ect;
4873
4874 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4875 lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4876
4877 /* remove the energy of our job from the ... */
4878 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4879
4880 newlb = end - (int)(energy / demands[lbcand]);
4881
4882 if( newlb > lst )
4883 {
4884 /* initialize conflict analysis if conflict analysis is applicable */
4886 {
4887 SCIP_Real relaxedbd;
4888
4889 /* analyze infeasibilty */
4891
4892 relaxedbd = lst + 1.0;
4893
4894 /* added to upper bound (which was overcut be new lower bound) of the variable */
4895 SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4896
4897 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4898 begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4899 conshdlrdata->usebdwidening, explanation) );
4900
4901 (*initialized) = TRUE;
4902 }
4903
4904 (*cutoff) = TRUE;
4905 break;
4906 }
4907 else if( newlb > newlbs[lbcand] )
4908 {
4909 INFERINFO inferinfo;
4910
4911 /* construct inference information */
4912 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4913
4914 /* buffer upper bound change */
4915 lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4916 newlbs[lbcand] = newlb;
4917 }
4918 }
4919
4920 /* check if the current interval has a smaller free energy */
4921 if( minavailable > freeenergy )
4922 {
4923 minavailable = freeenergy;
4924 minbegin = begin;
4925 }
4926 assert(minavailable >= 0);
4927 }
4928 }
4929
4930 return SCIP_OKAY;
4931}
4932
4933/** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4934static
4936 SCIP* scip, /**< SCIP data structure */
4937 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4938 int nvars, /**< number of start time variables (activities) */
4939 SCIP_VAR** vars, /**< array of start time variables */
4940 int* durations, /**< array of durations */
4941 int* demands, /**< array of demands */
4942 int capacity, /**< cumulative capacity */
4943 int hmin, /**< left bound of time axis to be considered (including hmin) */
4944 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4945 int* newlbs, /**< array to buffer new lower bounds */
4946 int* newubs, /**< array to buffer new upper bounds */
4947 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4948 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4949 int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
4950 int* flexenergies, /**< array of flexible energies in the same order as the variables */
4951 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
4952 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4953 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4954 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4955 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4956 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4957 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4958 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4959 )
4960{
4961 int coreEnergyAfterStart;
4962 SCIP_Longint maxavailable;
4963 SCIP_Longint minavailable;
4964 SCIP_Longint totalenergy;
4965 int nlcts;
4966 int begin;
4967 int minest;
4968 int maxlct;
4969 int start;
4970 int end;
4971 int v;
4972
4973 if( *cutoff )
4974 return SCIP_OKAY;
4975
4976 begin = hmin - 1;
4977
4978 minest = INT_MAX;
4979 maxlct = INT_MIN;
4980
4981 /* compute earliest start and latest completion time of all jobs */
4982 for( v = 0; v < nvars; ++v )
4983 {
4984 start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4985 end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4986
4987 minest = MIN(minest, start);
4988 maxlct = MAX(maxlct, end);
4989 }
4990
4991 /* adjust the effective time horizon */
4992 hmin = MAX(hmin, minest);
4993 hmax = MIN(hmax, maxlct);
4994
4995 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4996 totalenergy = computeTotalEnergy(durations, demands, nvars);
4997
4998 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4999 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5000 return SCIP_OKAY;
5001
5002 nlcts = 0;
5003
5004 /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5005 * define the start of the time interval under investigation
5006 */
5007 for( v = 0; v < nvars; ++v )
5008 {
5009 int flexenergy;
5010 int minend;
5011 int ubenergy;
5012 int ubcand;
5013 int est;
5014 int i;
5015
5016 est = ests[v];
5017
5018 /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5019 * infinity capacity is available; hence we skip that
5020 */
5021 if( est < hmin )
5022 continue;
5023
5024 /* if the earliest start time is larger or equal then hmax we have to stop */
5025 if( est >= hmax )
5026 break;
5027
5028 /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5029 * induced by start was just analyzed
5030 */
5031 if( est == begin )
5032 continue;
5033
5034 assert(est > begin);
5035
5036 SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5037
5038 begin = est;
5039 coreEnergyAfterStart = coreEnergyAfterEst[v];
5040
5041 flexenergy = 0;
5042 minavailable = maxavailable;
5043 minend = hmin;
5044 ubcand = -1;
5045 ubenergy = 0;
5046
5047 /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5048 * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5049 */
5050 for( i = nlcts; i < nvars; ++i )
5051 {
5052 SCIP_VAR* var;
5053 SCIP_Longint freeenergy;
5054 int duration;
5055 int demand;
5056 int idx;
5057 int lct;
5058 int ect;
5059
5060 idx = perm[i];
5061 assert(idx >= 0);
5062 assert(idx < nvars);
5063 assert(!(*cutoff));
5064
5065 /* the earliest start time of the job */
5066 lct = lcts[i];
5067
5068 /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5069 * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5070 */
5071 if( lct <= begin )
5072 {
5073 nlcts++;
5074 continue;
5075 }
5076
5077 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5078 * start with current beginning time
5079 */
5080 if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5081 break;
5082
5083 var = vars[idx];
5084 assert(var != NULL);
5085
5086 duration = durations[idx];
5087 assert(duration > 0);
5088
5089 demand = demands[idx];
5090 assert(demand > 0);
5091
5093
5094 /* the earliest completion time of the flexible part of the job */
5095 ect = ects[idx];
5096
5097 /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5098 * investigation; hence the overload check will do the the job
5099 */
5100 assert(lct >= minend);
5101 if( minavailable < maxavailable && lct > minend )
5102 {
5103 assert(!(*cutoff));
5104
5105 /* try to tighten the upper bound */
5106 SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5107 var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5108 initialized, explanation, cutoff) );
5109
5110 if( *cutoff )
5111 return SCIP_OKAY;
5112 }
5113
5114 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5115 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5116
5117 end = lct;
5118 assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5119
5120 /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5121 * free energy
5122 */
5123 if( end > hmax )
5124 break;
5125
5126 /* compute the contribution to the flexible energy */
5127 if( est >= begin )
5128 {
5129 /* if the jobs has to finish before the end, all the energy has to be scheduled */
5130 assert(ect <= end);
5131 assert(flexenergies[idx] >= 0);
5132 flexenergy += flexenergies[idx];
5133 }
5134 else
5135 {
5136 /* the job partly overlaps with the end */
5137 int candenergy;
5138 int energy;
5139
5140 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5141 * w.r.t. latest start time
5142 *
5143 * @note we need to be aware of the effective horizon
5144 */
5145 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5146 assert(ect - begin < duration);
5147 assert(energy >= 0);
5148
5149 /* adjust the flexible energy of the time interval */
5150 flexenergy += energy;
5151
5152 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5153 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5154 assert(candenergy >= 0);
5155
5156 /* check if we found a better candidate */
5157 if( candenergy > ubenergy )
5158 {
5159 ubenergy = candenergy;
5160 ubcand = idx;
5161 }
5162 }
5163
5164 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5165 assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5166
5167 /* compute the energy which is not used yet */
5168 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5169
5170 /* check overload */
5171 if( freeenergy < 0 )
5172 {
5173 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5174
5175 /* initialize conflict analysis if conflict analysis is applicable */
5177 {
5178 /* analyze infeasibilty */
5180
5181 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5183 conshdlrdata->usebdwidening, explanation) );
5184
5185 (*initialized) = TRUE;
5186 }
5187
5188 (*cutoff) = TRUE;
5189
5190 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5192
5193 return SCIP_OKAY;
5194 }
5195
5196 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5197 if( ubenergy > 0 && freeenergy < ubenergy )
5198 {
5199 SCIP_Longint energy;
5200 int newub;
5201 int lst;
5202
5203 duration = durations[ubcand];
5204 assert(duration > 0);
5205
5206 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5207 lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5208
5209 /* remove the energy of our job from the ... */
5210 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5211
5212 newub = begin - duration + (int)(energy / demands[ubcand]);
5213
5214 if( newub < ect - duration )
5215 {
5216 /* initialize conflict analysis if conflict analysis is applicable */
5218 {
5219 SCIP_Real relaxedbd;
5220 /* analyze infeasibilty */
5222
5223 relaxedbd = ect - duration - 1.0;
5224
5225 /* added to lower bound (which was undercut be new upper bound) of the variable */
5226 SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5227
5228 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5229 begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5230 conshdlrdata->usebdwidening, explanation) );
5231
5232 (*initialized) = TRUE;
5233 }
5234
5235 (*cutoff) = TRUE;
5236 return SCIP_OKAY;
5237 }
5238 else if( newub < newubs[ubcand] )
5239 {
5240 INFERINFO inferinfo;
5241
5242 /* construct inference information */
5243 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5244
5245 /* buffer upper bound change */
5246 ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5247 newubs[ubcand] = newub;
5248 }
5249 }
5250
5251 /* check if the current interval has a smaller free energy */
5252 if( minavailable > freeenergy )
5253 {
5254 minavailable = freeenergy;
5255 minend = end;
5256 }
5257 assert(minavailable >= 0);
5258 }
5259 }
5260
5261 return SCIP_OKAY;
5262}
5263
5264/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5265 * edge-finding
5266 *
5267 * @note The algorithm is based on the following two papers:
5268 * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5269 * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5270 * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5271 * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5272 * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5273 */
5274static
5276 SCIP* scip, /**< SCIP data structure */
5277 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5278 SCIP_PROFILE* profile, /**< current core profile */
5279 int nvars, /**< number of start time variables (activities) */
5280 SCIP_VAR** vars, /**< array of start time variables */
5281 int* durations, /**< array of durations */
5282 int* demands, /**< array of demands */
5283 int capacity, /**< cumulative capacity */
5284 int hmin, /**< left bound of time axis to be considered (including hmin) */
5285 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5286 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5287 int* nchgbds, /**< pointer to store the number of bound changes */
5288 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5289 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5290 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5291 )
5292{
5293 int* coreEnergyAfterEst;
5294 int* coreEnergyAfterLct;
5295 int* flexenergies;
5296 int* permests;
5297 int* permlcts;
5298 int* lcts;
5299 int* ests;
5300 int* ects;
5301 int* lsts;
5302
5303 int* newlbs;
5304 int* newubs;
5305 int* lbinferinfos;
5306 int* ubinferinfos;
5307
5308 int v;
5309
5310 /* check if a cutoff was already detected */
5311 if( (*cutoff) )
5312 return SCIP_OKAY;
5313
5314 /* check if at least the basic overload checking should be perfomed */
5315 if( !conshdlrdata->ttefcheck )
5316 return SCIP_OKAY;
5317
5318 SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5319
5320 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5321 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5322 SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5323 SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5324 SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5325 SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5326 SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5327 SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5328 SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5329
5330 SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5331 SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5332 SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5333 SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5334
5335 /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5336 for( v = 0; v < nvars; ++v )
5337 {
5338 newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5339 newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5340 lbinferinfos[v] = 0;
5341 ubinferinfos[v] = 0;
5342 }
5343
5344 /* collect earliest start times, latest completion time, and free energy contributions */
5345 collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5346
5347 /* sort the earliest start times and latest completion in non-decreasing order */
5348 SCIPsortIntInt(ests, permests, nvars);
5349 SCIPsortIntInt(lcts, permlcts, nvars);
5350
5351 /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5352 * points
5353 */
5354 computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5355
5356 /* propagate the upper bounds and "opportunistically" the lower bounds */
5357 SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5358 newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5359 permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5360
5361 /* propagate the lower bounds and "opportunistically" the upper bounds */
5362 SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5363 newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5364 permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5365
5366 /* apply the buffer bound changes */
5367 for( v = 0; v < nvars && !(*cutoff); ++v )
5368 {
5369 SCIP_Bool infeasible;
5370 SCIP_Bool tightened;
5371
5372 if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5373 {
5374 SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5375 TRUE, &infeasible, &tightened) );
5376 }
5377 else
5378 {
5379 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5380 }
5381
5382 /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5383 assert(!infeasible);
5384
5385 if( tightened )
5386 {
5387 (*nchgbds)++;
5388
5389 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5391 }
5392
5393 if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5394 {
5395 SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5396 TRUE, &infeasible, &tightened) );
5397 }
5398 else
5399 {
5400 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5401 }
5402
5403 /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5404 * bound update can be infeasible
5405 */
5406 if( infeasible )
5407 {
5408 /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5409 * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5410 * be analyzed in the case when begin and end exceed the 15 bit limit
5411 */
5413 {
5414 INFERINFO inferinfo;
5415 SCIP_VAR* var;
5416 int begin;
5417 int end;
5418
5419 var = vars[v];
5420 assert(var != NULL);
5421
5422 /* initialize conflict analysis */
5424
5425 /* convert int to inference information */
5426 inferinfo = intToInferInfo(ubinferinfos[v]);
5427
5428 /* collect time window from inference information */
5429 begin = inferInfoGetData1(inferinfo);
5430 end = inferInfoGetData2(inferinfo);
5431 assert(begin < end);
5432
5433 /* added to lower bound (which was undercut be new upper bound) of the variable */
5435
5436 /* analysis the upper bound change */
5437 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5438 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5439 conshdlrdata->usebdwidening, explanation) );
5440
5441 (*initialized) = TRUE;
5442 }
5443
5444 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5446
5447 (*cutoff) = TRUE;
5448 break;
5449 }
5450
5451 if( tightened )
5452 {
5453 (*nchgbds)++;
5454
5455 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5457 }
5458 }
5459
5460 SCIPfreeBufferArray(scip, &ubinferinfos);
5461 SCIPfreeBufferArray(scip, &lbinferinfos);
5462 SCIPfreeBufferArray(scip, &newubs);
5463 SCIPfreeBufferArray(scip, &newlbs);
5464
5465 /* free buffer arrays */
5466 SCIPfreeBufferArray(scip, &lsts);
5467 SCIPfreeBufferArray(scip, &ects);
5468 SCIPfreeBufferArray(scip, &ests);
5469 SCIPfreeBufferArray(scip, &lcts);
5470 SCIPfreeBufferArray(scip, &permests);
5471 SCIPfreeBufferArray(scip, &permlcts);
5472 SCIPfreeBufferArray(scip, &flexenergies);
5473 SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5474 SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5475
5476 return SCIP_OKAY;
5477}
5478
5479/** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5480 * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5481 * time table propagator
5482 */
5483static
5485 SCIP* scip, /**< SCIP data structure */
5486 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5487 SCIP_PROFILE* profile, /**< core profile */
5488 int nvars, /**< number of start time variables (activities) */
5489 SCIP_VAR** vars, /**< array of start time variables */
5490 int* durations, /**< array of durations */
5491 int* demands, /**< array of demands */
5492 int capacity, /**< cumulative capacity */
5493 int hmin, /**< left bound of time axis to be considered (including hmin) */
5494 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5495 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5496 int* nchgbds, /**< pointer to store the number of bound changes */
5497 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5498 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5499 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5500 )
5501{
5502 SCIP_Bool infeasible;
5503 int v;
5504
5505 assert(scip != NULL);
5506 assert(nvars > 0);
5507 assert(cons != NULL);
5508 assert(cutoff != NULL);
5509
5510 /* check if already a cutoff was detected */
5511 if( (*cutoff) )
5512 return SCIP_OKAY;
5513
5514 /* check if the time tabling should infer bounds */
5515 if( !conshdlrdata->ttinfer )
5516 return SCIP_OKAY;
5517
5518 assert(*initialized == FALSE);
5519
5520 SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5521 SCIPconsGetName(cons), hmin, hmax, capacity);
5522
5523 infeasible = FALSE;
5524
5525 /* if core profile is empty; nothing to do */
5526 if( SCIPprofileGetNTimepoints(profile) <= 1 )
5527 return SCIP_OKAY;
5528
5529 /* start checking each job whether the bounds can be improved */
5530 for( v = 0; v < nvars; ++v )
5531 {
5532 SCIP_VAR* var;
5533 int demand;
5534 int duration;
5535 int begin;
5536 int end;
5537 int est;
5538 int lst;
5539
5540 var = vars[v];
5541 assert(var != NULL);
5542
5543 duration = durations[v];
5544 assert(duration > 0);
5545
5546 /* collect earliest and latest start time */
5549
5550 /* check if the start time variables is already fixed; in that case we can ignore the job */
5551 if( est == lst )
5552 continue;
5553
5554 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5555 if( lst + duration <= hmin || est >= hmax )
5556 continue;
5557
5558 /* compute core interval w.r.t. effective time horizon */
5559 begin = MAX(hmin, lst);
5560 end = MIN(hmax, est + duration);
5561
5562 demand = demands[v];
5563 assert(demand > 0);
5564
5565 /* if the job has a core, remove it first */
5566 if( begin < end )
5567 {
5568 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5569 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5570
5571 SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5572 }
5573
5574 /* first try to update the earliest start time */
5575 SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5576 profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5577
5578 if( *cutoff )
5579 break;
5580
5581 /* second try to update the latest start time */
5582 SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5583 profile, v, nchgbds) );
5584
5585 if( *cutoff )
5586 break;
5587
5588 /* collect the potentially updated earliest and latest start time */
5591
5592 /* compute core interval w.r.t. effective time horizon */
5593 begin = MAX(hmin, lst);
5594 end = MIN(hmax, est + duration);
5595
5596 /* after updating the bound we might have a new core */
5597 if( begin < end )
5598 {
5599 int pos;
5600
5601 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5602 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5603
5604 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5605
5606 if( infeasible )
5607 {
5608 /* use conflict analysis to analysis the core insertion which was infeasible */
5609 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5610 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5611
5612 if( explanation != NULL )
5613 explanation[v] = TRUE;
5614
5615 (*cutoff) = TRUE;
5616
5617 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5619
5620 break;
5621 }
5622 }
5623 }
5624
5625 return SCIP_OKAY;
5626}
5627
5628
5629/** node data structure for the binary tree used for edgefinding (with overload checking) */
5630struct SCIP_NodeData
5631{
5632 SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5633 SCIP_Real key; /**< key which is to insert the corresponding search node */
5634 int est; /**< earliest start time if the node data belongs to a leaf */
5635 int lct; /**< latest completion time if the node data belongs to a leaf */
5636 int demand; /**< demand of the job if the node data belongs to a leaf */
5637 int duration; /**< duration of the job if the node data belongs to a leaf */
5638 int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5639 int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5640 SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5641 int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5642 int energylambda;
5643 SCIP_Longint enveloplambda;
5644 int idx; /**< index of the start time variable in the (global) variable array */
5645 SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5646};
5647typedef struct SCIP_NodeData SCIP_NODEDATA;
5648
5649
5650/** update node data structure starting from the given node along the path to the root node */
5651static
5653 SCIP* scip, /**< SCIP data structure */
5654 SCIP_BTNODE* node /**< search node which inserted */
5655 )
5656{
5657 SCIP_BTNODE* left;
5658 SCIP_BTNODE* right;
5660 SCIP_NODEDATA* leftdata;
5661 SCIP_NODEDATA* rightdata;
5662
5663 SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5664
5665 if( SCIPbtnodeIsLeaf(node) )
5666 node = SCIPbtnodeGetParent(node);
5667
5668 while( node != NULL )
5669 {
5670 /* get node data */
5672 assert(nodedata != NULL);
5673
5674 /* collect node data from left node */
5675 left = SCIPbtnodeGetLeftchild(node);
5676 assert(left != NULL);
5677 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5678 assert(leftdata != NULL);
5679
5680 /* collect node data from right node */
5681 right = SCIPbtnodeGetRightchild(node);
5682 assert(right != NULL);
5683 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5684 assert(rightdata != NULL);
5685
5686 /* update envelop and energy */
5687 if( leftdata->enveloptheta >= 0 )
5688 {
5689 assert(rightdata->energytheta != -1);
5690 nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5691 }
5692 else
5693 nodedata->enveloptheta = rightdata->enveloptheta;
5694
5695 assert(leftdata->energytheta != -1);
5696 assert(rightdata->energytheta != -1);
5697 nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5698
5699 if( leftdata->enveloplambda >= 0 )
5700 {
5701 assert(rightdata->energytheta != -1);
5702 nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5703 }
5704 else
5705 nodedata->enveloplambda = rightdata->enveloplambda;
5706
5707 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5708 nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5709
5710 SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5711
5712 if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5713 {
5714 assert(rightdata->energytheta != -1);
5715 assert(leftdata->energytheta != -1);
5716 nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5717 }
5718 else if( rightdata->energylambda >= 0 )
5719 {
5720 assert(leftdata->energytheta != -1);
5721 nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5722 }
5723 else if( leftdata->energylambda >= 0 )
5724 {
5725 assert(rightdata->energytheta != -1);
5726 nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5727 }
5728 else
5729 nodedata->energylambda = -1;
5730
5731 /* go to parent */
5732 node = SCIPbtnodeGetParent(node);
5733 }
5734
5735 SCIPdebugMsg(scip, "updating done\n");
5736}
5737
5738/** updates the key of the first parent on the trace which comes from left */
5739static
5741 SCIP_BTNODE* node, /**< node to start the trace */
5742 SCIP_Real key /**< update search key */
5743 )
5744{
5745 assert(node != NULL);
5746
5747 while( !SCIPbtnodeIsRoot(node) )
5748 {
5749 SCIP_BTNODE* parent;
5750
5751 parent = SCIPbtnodeGetParent(node);
5752 assert(parent != NULL);
5753
5754 if( SCIPbtnodeIsLeftchild(node) )
5755 {
5757
5759 assert(nodedata != NULL);
5760
5761 nodedata->key = key;
5762 return;
5763 }
5764
5765 node = parent;
5766 }
5767}
5768
5769
5770/** deletes the given node and updates all envelops */
5771static
5773 SCIP* scip, /**< SCIP data structure */
5774 SCIP_BT* tree, /**< binary tree */
5775 SCIP_BTNODE* node /**< node to be deleted */
5776 )
5777{
5778 SCIP_BTNODE* parent;
5779 SCIP_BTNODE* grandparent;
5780 SCIP_BTNODE* sibling;
5781
5782 assert(scip != NULL);
5783 assert(tree != NULL);
5784 assert(node != NULL);
5785
5786 assert(SCIPbtnodeIsLeaf(node));
5787 assert(!SCIPbtnodeIsRoot(node));
5788
5789 SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5790
5791 parent = SCIPbtnodeGetParent(node);
5792 assert(parent != NULL);
5793 if( SCIPbtnodeIsLeftchild(node) )
5794 {
5795 sibling = SCIPbtnodeGetRightchild(parent);
5797 }
5798 else
5799 {
5800 sibling = SCIPbtnodeGetLeftchild(parent);
5802 }
5803 assert(sibling != NULL);
5804
5805 grandparent = SCIPbtnodeGetParent(parent);
5806
5807 if( grandparent != NULL )
5808 {
5809 /* reset parent of sibling */
5810 SCIPbtnodeSetParent(sibling, grandparent);
5811
5812 /* reset child of grandparent to sibling */
5813 if( SCIPbtnodeIsLeftchild(parent) )
5814 {
5815 SCIPbtnodeSetLeftchild(grandparent, sibling);
5816 }
5817 else
5818 {
5820
5821 assert(SCIPbtnodeIsRightchild(parent));
5822 SCIPbtnodeSetRightchild(grandparent, sibling);
5823
5825
5826 updateKeyOnTrace(grandparent, nodedata->key);
5827 }
5828
5829 updateEnvelope(scip, grandparent);
5830 }
5831 else
5832 {
5833 SCIPbtnodeSetParent(sibling, NULL);
5834
5835 SCIPbtSetRoot(tree, sibling);
5836 }
5837
5838 SCIPbtnodeFree(tree, &parent);
5839
5840 return SCIP_OKAY;
5841}
5842
5843/** moves a node form the theta set into the lambda set and updates the envelops */
5844static
5846 SCIP* scip, /**< SCIP data structure */
5847 SCIP_BT* tree, /**< binary tree */
5848 SCIP_BTNODE* node /**< node to move into the lambda set */
5849 )
5850{
5852
5853 assert(scip != NULL);
5854 assert(tree != NULL);
5855 assert(node != NULL);
5856
5858 assert(nodedata != NULL);
5859 assert(nodedata->intheta);
5860
5861 /* move the contributions form the theta set into the lambda set */
5862 assert(nodedata->enveloptheta != -1);
5863 assert(nodedata->energytheta != -1);
5864 assert(nodedata->enveloplambda == -1);
5865 assert(nodedata->energylambda == -1);
5866 nodedata->enveloplambda = nodedata->enveloptheta;
5867 nodedata->energylambda = nodedata->energytheta;
5868
5869 nodedata->enveloptheta = -1;
5870 nodedata->energytheta = 0;
5871 nodedata->intheta = FALSE;
5872
5873 /* update the energy and envelop values on trace */
5874 updateEnvelope(scip, node);
5875
5876 return SCIP_OKAY;
5877}
5878
5879/** inserts a node into the theta set and update the envelops */
5880static
5882 SCIP* scip, /**< SCIP data structure */
5883 SCIP_BT* tree, /**< binary tree */
5884 SCIP_BTNODE* node, /**< node to insert */
5885 SCIP_NODEDATA* nodedatas, /**< array of node data */
5886 int* nodedataidx, /**< array of indices for node data */
5887 int* nnodedatas /**< pointer to number of node data */
5888 )
5889{
5890 /* if the tree is empty the node will be the root node */
5891 if( SCIPbtIsEmpty(tree) )
5892 {
5893 SCIPbtSetRoot(tree, node);
5894 }
5895 else
5896 {
5897 SCIP_NODEDATA* newnodedata;
5898 SCIP_NODEDATA* leafdata;
5900 SCIP_BTNODE* leaf;
5901 SCIP_BTNODE* newnode;
5902 SCIP_BTNODE* parent;
5903
5904 leaf = SCIPbtGetRoot(tree);
5905 assert(leaf != NULL);
5906
5907 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5908 assert(leafdata != NULL);
5909
5911 assert(nodedata != NULL);
5912 assert(nodedata->intheta);
5913
5914 /* find the position to insert the node */
5915 while( !SCIPbtnodeIsLeaf(leaf) )
5916 {
5917 if( nodedata->key < leafdata->key )
5918 leaf = SCIPbtnodeGetLeftchild(leaf);
5919 else
5920 leaf = SCIPbtnodeGetRightchild(leaf);
5921
5922 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5923 assert(leafdata != NULL);
5924 }
5925
5926 assert(leaf != NULL);
5927 assert(leaf != node);
5928
5929 /* store node data to be able to delete them latter */
5930 newnodedata = &nodedatas[*nnodedatas];
5931 nodedataidx[*nnodedatas] = *nnodedatas;
5932 ++(*nnodedatas);
5933
5934 /* init node data */
5935 newnodedata->var = NULL;
5936 newnodedata->key = SCIP_INVALID;
5937 newnodedata->est = INT_MIN;
5938 newnodedata->lct = INT_MAX;
5939 newnodedata->duration = 0;
5940 newnodedata->demand = 0;
5941 newnodedata->enveloptheta = -1;
5942 newnodedata->energytheta = 0;
5943 newnodedata->enveloplambda = -1;
5944 newnodedata->energylambda = -1;
5945 newnodedata->idx = -1;
5946 newnodedata->intheta = TRUE;
5947
5948 /* create a new node */
5949 SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
5950 assert(newnode != NULL);
5951
5952 parent = SCIPbtnodeGetParent(leaf);
5953
5954 if( parent != NULL )
5955 {
5956 SCIPbtnodeSetParent(newnode, parent);
5957
5958 /* check if the node is the left child */
5959 if( SCIPbtnodeGetLeftchild(parent) == leaf )
5960 {
5961 SCIPbtnodeSetLeftchild(parent, newnode);
5962 }
5963 else
5964 {
5965 SCIPbtnodeSetRightchild(parent, newnode);
5966 }
5967 }
5968 else
5969 SCIPbtSetRoot(tree, newnode);
5970
5971 if( nodedata->key < leafdata->key )
5972 {
5973 /* node is on the left */
5974 SCIPbtnodeSetLeftchild(newnode, node);
5975 SCIPbtnodeSetRightchild(newnode, leaf);
5976 newnodedata->key = nodedata->key;
5977 }
5978 else
5979 {
5980 /* leaf is on the left */
5981 SCIPbtnodeSetLeftchild(newnode, leaf);
5982 SCIPbtnodeSetRightchild(newnode, node);
5983 newnodedata->key = leafdata->key;
5984 }
5985
5986 SCIPbtnodeSetParent(leaf, newnode);
5987 SCIPbtnodeSetParent(node, newnode);
5988 }
5989
5990 /* update envelop */
5991 updateEnvelope(scip, node);
5992
5993 return SCIP_OKAY;
5994}
5995
5996/** returns the leaf responsible for the lambda energy */
5997static
5999 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6000 )
6001{
6002 SCIP_BTNODE* left;
6003 SCIP_BTNODE* right;
6005 SCIP_NODEDATA* leftdata;
6006 SCIP_NODEDATA* rightdata;
6007
6008 assert(node != NULL);
6009
6011 assert(nodedata != NULL);
6012
6013 /* check if the node is the (responsible) leaf */
6014 if( SCIPbtnodeIsLeaf(node) )
6015 {
6016 assert(!nodedata->intheta);
6017 return node;
6018 }
6019
6020 left = SCIPbtnodeGetLeftchild(node);
6021 assert(left != NULL);
6022
6023 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6024 assert(leftdata != NULL);
6025
6026 right = SCIPbtnodeGetRightchild(node);
6027 assert(right != NULL);
6028
6029 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6030 assert(rightdata != NULL);
6031
6032 assert(nodedata->energylambda != -1);
6033 assert(rightdata->energytheta != -1);
6034
6035 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6037
6038 assert(leftdata->energytheta != -1);
6039 assert(rightdata->energylambda != -1);
6040 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6041
6043}
6044
6045/** returns the leaf responsible for the lambda envelop */
6046static
6048 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6049 )
6050{
6051 SCIP_BTNODE* left;
6052 SCIP_BTNODE* right;
6054 SCIP_NODEDATA* leftdata;
6055 SCIP_NODEDATA* rightdata;
6056
6057 assert(node != NULL);
6058
6060 assert(nodedata != NULL);
6061
6062 /* check if the node is the (responsible) leaf */
6063 if( SCIPbtnodeIsLeaf(node) )
6064 {
6065 assert(!nodedata->intheta);
6066 return node;
6067 }
6068
6069 left = SCIPbtnodeGetLeftchild(node);
6070 assert(left != NULL);
6071
6072 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6073 assert(leftdata != NULL);
6074
6075 right = SCIPbtnodeGetRightchild(node);
6076 assert(right != NULL);
6077
6078 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6079 assert(rightdata != NULL);
6080
6081 assert(nodedata->enveloplambda != -1);
6082 assert(rightdata->energytheta != -1);
6083
6084 /* check if the left or right child is the one defining the envelop for the lambda set */
6085 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6087 else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6088 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6090
6091 assert(rightdata->enveloplambda != -1);
6092 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6093
6095}
6096
6097
6098/** reports all elements from set theta to generate a conflicting set */
6099static
6101 SCIP_BTNODE* node, /**< node within a theta subtree */
6102 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6103 int* nelements, /**< pointer to store the number of elements in omegaset */
6104 int* est, /**< pointer to store the earliest start time of the omega set */
6105 int* lct, /**< pointer to store the latest start time of the omega set */
6106 int* energy /**< pointer to store the energy of the omega set */
6107 )
6108{
6110
6112 assert(nodedata != NULL);
6113
6114 if( !SCIPbtnodeIsLeaf(node) )
6115 {
6116 collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6117 collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6118 }
6119 else if( nodedata->intheta )
6120 {
6121 assert(nodedata->var != NULL);
6122 SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6123
6124 omegaset[*nelements] = node;
6125 (*est) = MIN(*est, nodedata->est);
6126 (*lct) = MAX(*lct, nodedata->lct);
6127 (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6128 (*nelements)++;
6129 }
6130}
6131
6132
6133/** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6134static
6136 SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6137 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6138 int* nelements, /**< pointer to store the number of elements in omegaset */
6139 int* est, /**< pointer to store the earliest start time of the omega set */
6140 int* lct, /**< pointer to store the latest start time of the omega set */
6141 int* energy /**< pointer to store the energy of the omega set */
6142 )
6143{
6144 assert(node != NULL);
6145
6146 if( SCIPbtnodeIsLeaf(node) )
6147 {
6148 collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6149 }
6150 else
6151 {
6152 SCIP_BTNODE* left;
6153 SCIP_BTNODE* right;
6155 SCIP_NODEDATA* leftdata;
6156 SCIP_NODEDATA* rightdata;
6157
6159 assert(nodedata != NULL);
6160
6161 left = SCIPbtnodeGetLeftchild(node);
6162 assert(left != NULL);
6163
6164 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6165 assert(leftdata != NULL);
6166
6167 right = SCIPbtnodeGetRightchild(node);
6168 assert(right != NULL);
6169
6170 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6171 assert(rightdata != NULL);
6172
6174 assert(nodedata != NULL);
6175
6176 assert(nodedata->enveloptheta != -1);
6177 assert(rightdata->energytheta != -1);
6178
6179 if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6180 {
6181 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6182 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6183 }
6184 else
6185 {
6186 assert(rightdata->enveloptheta != -1);
6187 assert(nodedata->enveloptheta == rightdata->enveloptheta);
6188 traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6189 }
6190 }
6191}
6192
6193/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6194static
6196 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6197 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6198 int* nelements, /**< pointer to store the number of elements in omega set */
6199 int* est, /**< pointer to store the earliest start time of the omega set */
6200 int* lct, /**< pointer to store the latest start time of the omega set */
6201 int* energy /**< pointer to store the energy of the omega set */
6202 )
6203{
6204 SCIP_BTNODE* left;
6205 SCIP_BTNODE* right;
6207 SCIP_NODEDATA* leftdata;
6208 SCIP_NODEDATA* rightdata;
6209
6210 assert(node != NULL);
6211
6213 assert(nodedata != NULL);
6214
6215 /* check if the node is a leaf */
6216 if( SCIPbtnodeIsLeaf(node) )
6217 return;
6218
6219 left = SCIPbtnodeGetLeftchild(node);
6220 assert(left != NULL);
6221
6222 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6223 assert(leftdata != NULL);
6224
6225 right = SCIPbtnodeGetRightchild(node);
6226 assert(right != NULL);
6227
6228 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6229 assert(rightdata != NULL);
6230
6231 assert(nodedata->energylambda != -1);
6232 assert(rightdata->energytheta != -1);
6233
6234 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6235 {
6236 traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6237 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6238 }
6239 else
6240 {
6241 assert(leftdata->energytheta != -1);
6242 assert(rightdata->energylambda != -1);
6243 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6244
6245 collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6246 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6247 }
6248}
6249
6250/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6251static
6253 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6254 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6255 int* nelements, /**< pointer to store the number of elements in omega set */
6256 int* est, /**< pointer to store the earliest start time of the omega set */
6257 int* lct, /**< pointer to store the latest start time of the omega set */
6258 int* energy /**< pointer to store the energy of the omega set */
6259 )
6260{
6261 SCIP_BTNODE* left;
6262 SCIP_BTNODE* right;
6264 SCIP_NODEDATA* leftdata;
6265 SCIP_NODEDATA* rightdata;
6266
6267 assert(node != NULL);
6268
6270 assert(nodedata != NULL);
6271
6272 /* check if the node is a leaf */
6273 if( SCIPbtnodeIsLeaf(node) )
6274 {
6275 assert(!nodedata->intheta);
6276 return;
6277 }
6278
6279 left = SCIPbtnodeGetLeftchild(node);
6280 assert(left != NULL);
6281
6282 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6283 assert(leftdata != NULL);
6284
6285 right = SCIPbtnodeGetRightchild(node);
6286 assert(right != NULL);
6287
6288 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6289 assert(rightdata != NULL);
6290
6291 assert(nodedata->enveloplambda != -1);
6292 assert(rightdata->energytheta != -1);
6293
6294 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6295 {
6296 traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6297 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6298 }
6299 else
6300 {
6301 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6302 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6303 {
6304 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6305 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6306 }
6307 else
6308 {
6309 assert(rightdata->enveloplambda != -1);
6310 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6311 traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6312 }
6313 }
6314}
6315
6316/** compute the energy contribution by job which corresponds to the given leaf */
6317static
6319 SCIP_BTNODE* node /**< leaf */
6320 )
6321{
6323 int duration;
6324
6326 assert(nodedata != NULL);
6327 assert(nodedata->var != NULL);
6328
6329 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6330 assert(duration > 0);
6331
6332 SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6334 SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6335
6336 /* return energy which is contributed by the start time variable */
6337 return nodedata->demand * duration;
6338}
6339
6340/** comparison method for two node data w.r.t. the earliest start time */
6341static
6343{
6344 int est1;
6345 int est2;
6346
6347 est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6348 est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6349
6350 return (est1 - est2);
6351}
6352
6353/** comparison method for two node data w.r.t. the latest completion time */
6354static
6356{
6357 SCIP_NODEDATA* nodedatas;
6358
6359 nodedatas = (SCIP_NODEDATA*) dataptr;
6360 return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6361}
6362
6363
6364/** an overload was detected; initialized conflict analysis, add an initial reason
6365 *
6366 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6367 */
6368static
6370 SCIP* scip, /**< SCIP data structure */
6371 SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6372 int capacity, /**< cumulative capacity */
6373 int nleaves, /**< number of responsible leaves */
6374 int est, /**< earliest start time of the ...... */
6375 int lct, /**< latest completly time of the .... */
6376 int reportedenergy, /**< energy which already reported */
6377 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6378 int shift, /**< shift applied to all jobs before adding them to the tree */
6379 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6380 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6381 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6382 )
6383{
6384 SCIP_Longint energy;
6385 int j;
6386
6387 /* do nothing if conflict analysis is not applicable */
6389 return SCIP_OKAY;
6390
6391 SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6392
6393 /* compute energy of initial time window */
6394 energy = ((SCIP_Longint) lct - est) * capacity;
6395
6396 /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6397 SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6398
6399 /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6400 * thereby, compute the time window of interest
6401 */
6402 for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6403 {
6405
6407 assert(nodedata != NULL);
6408
6409 reportedenergy += computeEnergyContribution(leaves[j]);
6410
6411 /* adjust energy if the earliest start time decrease */
6412 if( nodedata->est < est )
6413 {
6414 est = nodedata->est;
6415 energy = ((SCIP_Longint) lct - est) * capacity;
6416 }
6417 }
6418 assert(reportedenergy > energy);
6419
6420 SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6421
6422 /* initialize conflict analysis */
6424
6425 /* flip earliest start time and latest completion time */
6426 if( !propest )
6427 {
6428 SCIPswapInts(&est, &lct);
6429
6430 /* shift earliest start time and latest completion time */
6431 lct = shift - lct;
6432 est = shift - est;
6433 }
6434 else
6435 {
6436 /* shift earliest start time and latest completion time */
6437 lct = lct + shift;
6438 est = est + shift;
6439 }
6440
6441 nleaves = j;
6442
6443 /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6444 * overloaded
6445 */
6446 for( j = nleaves-1; j >= 0; --j )
6447 {
6449
6451 assert(nodedata != NULL);
6452 assert(nodedata->var != NULL);
6453
6454 /* check if bound widening should be used */
6455 if( usebdwidening )
6456 {
6457 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6458 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6459 }
6460 else
6461 {
6464 }
6465
6466 if( explanation != NULL )
6467 explanation[nodedata->idx] = TRUE;
6468 }
6469
6470 (*initialized) = TRUE;
6471
6472 return SCIP_OKAY;
6473}
6474
6475/** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6476 * responsible interval bounds in *est_omega and *lct_omega
6477 */
6478static
6480 SCIP* scip, /**< SCIP data structure */
6481 int duration, /**< duration of the job to move */
6482 int demand, /**< demand of the job to move */
6483 int capacity, /**< cumulative capacity */
6484 int est, /**< earliest start time of the omega set */
6485 int lct, /**< latest start time of the omega set */
6486 int energy /**< energy of the omega set */
6487 )
6488{
6489 int newest;
6490
6491 newest = 0;
6492
6493 assert(scip != NULL);
6494
6495 if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6496 {
6497 if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6498 {
6499 newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6500 newest += est;
6501 }
6502 }
6503
6504 return newest;
6505}
6506
6507/** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6508 *
6509 * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6510 * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6511 */
6512static
6514 SCIP* scip, /**< SCIP data structure */
6515 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6516 SCIP_CONS* cons, /**< constraint which is propagated */
6517 SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6518 SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6519 int capacity, /**< cumulative capacity */
6520 int ncands, /**< number of candidates */
6521 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6522 int shift, /**< shift applied to all jobs before adding them to the tree */
6523 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6524 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6525 int* nchgbds, /**< pointer to store the number of bound changes */
6526 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6527 )
6528{
6529 SCIP_NODEDATA* rootdata;
6530 int j;
6531
6532 assert(!SCIPbtIsEmpty(tree));
6533
6534 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6535 assert(rootdata != NULL);
6536
6537 /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6538 for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6539 {
6541
6542 if( SCIPbtnodeIsRoot(leaves[j]) )
6543 break;
6544
6546 assert(nodedata->est != -1);
6547
6548 /* check if the root lambda envelop exeeds the available capacity */
6549 while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6550 {
6551 SCIP_BTNODE** omegaset;
6552 SCIP_BTNODE* leaf;
6553 SCIP_NODEDATA* leafdata;
6554 int nelements;
6555 int energy;
6556 int newest;
6557 int est;
6558 int lct;
6559
6560 assert(!(*cutoff));
6561
6562 /* find responsible leaf for the lambda envelope */
6564 assert(leaf != NULL);
6565 assert(SCIPbtnodeIsLeaf(leaf));
6566
6567 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6568 assert(leafdata != NULL);
6569 assert(!leafdata->intheta);
6570 assert(leafdata->duration > 0);
6571 assert(leafdata->est >= 0);
6572
6573 /* check if the job has to be removed since its latest completion is to large */
6574 if( leafdata->est + leafdata->duration >= nodedata->lct )
6575 {
6576 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6577
6578 /* the root might changed therefore we need to collect the new root node data */
6579 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6580 assert(rootdata != NULL);
6581
6582 continue;
6583 }
6584
6585 /* compute omega set */
6586 SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6587
6588 nelements = 0;
6589 est = INT_MAX;
6590 lct = INT_MIN;
6591 energy = 0;
6592
6593 /* collect the omega set from theta set */
6594 traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6595 assert(nelements > 0);
6596 assert(nelements < ncands);
6597
6598 newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6599
6600 /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6601 if( newest > lct )
6602 {
6603 SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6604
6605 /* analyze over load */
6606 SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6607 conshdlrdata->usebdwidening, initialized, explanation) );
6608 (*cutoff) = TRUE;
6609
6610 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6612 }
6613 else if( newest > 0 )
6614 {
6615 SCIP_Bool infeasible;
6616 SCIP_Bool tightened;
6617 INFERINFO inferinfo;
6618
6619 if( propest )
6620 {
6621 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6622 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6623
6624 SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6625 SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6626
6627 if( inferInfoIsValid(inferinfo) )
6628 {
6629 SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6630 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6631 }
6632 else
6633 {
6634 SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6635 TRUE, &infeasible, &tightened) );
6636 }
6637
6638 /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6640 }
6641 else
6642 {
6643 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6644 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6645
6646 SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6647 SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6648
6649 if( inferInfoIsValid(inferinfo) )
6650 {
6651 SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6652 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6653 }
6654 else
6655 {
6656 SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6657 TRUE, &infeasible, &tightened) );
6658 }
6659
6660 /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6662 }
6663
6664 /* adjust the earliest start time */
6665 if( tightened )
6666 {
6667 leafdata->est = newest;
6668 (*nchgbds)++;
6669 }
6670
6671 if( infeasible )
6672 {
6673 /* initialize conflict analysis if conflict analysis is applicable */
6675 {
6676 int i;
6677
6678 SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6679
6681
6682 /* add lower and upper bound of variable which leads to the infeasibilty */
6683 SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6684 SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6685
6686 if( explanation != NULL )
6687 explanation[leafdata->idx] = TRUE;
6688
6689 /* add lower and upper bound of variable which lead to the infeasibilty */
6690 for( i = 0; i < nelements; ++i )
6691 {
6692 nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6693 assert(nodedata != NULL);
6694
6697
6698 if( explanation != NULL )
6699 explanation[nodedata->idx] = TRUE;
6700 }
6701
6702 (*initialized) = TRUE;
6703 }
6704
6705 (*cutoff) = TRUE;
6706
6707 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6709 }
6710 }
6711
6712 /* free omegaset array */
6713 SCIPfreeBufferArray(scip, &omegaset);
6714
6715 /* delete responsible leaf from lambda */
6716 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6717
6718 /* the root might changed therefore we need to collect the new root node data */
6719 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6720 assert(rootdata != NULL);
6721 }
6722
6723 /* move current job j from the theta set into the lambda set */
6724 SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6725 }
6726
6727 return SCIP_OKAY;
6728}
6729
6730/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6731 *
6732 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6733 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6734 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6735 */
6736static
6738 SCIP* scip, /**< SCIP data structure */
6739 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6740 int nvars, /**< number of start time variables (activities) */
6741 SCIP_VAR** vars, /**< array of start time variables */
6742 int* durations, /**< array of durations */
6743 int* demands, /**< array of demands */
6744 int capacity, /**< cumulative capacity */
6745 int hmin, /**< left bound of time axis to be considered (including hmin) */
6746 int hmax, /**< right bound of time axis to be considered (not including hmax) */
6747 SCIP_CONS* cons, /**< constraint which is propagated */
6748 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6749 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6750 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6751 int* nchgbds, /**< pointer to store the number of bound changes */
6752 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6753 )
6754{
6755 SCIP_NODEDATA* nodedatas;
6756 SCIP_BTNODE** leaves;
6757 SCIP_BT* tree;
6758 int* nodedataidx;
6759
6760 int totalenergy;
6761 int nnodedatas;
6762 int ninsertcands;
6763 int ncands;
6764
6765 int shift;
6766 int idx = -1;
6767 int j;
6768
6769 assert(scip != NULL);
6770 assert(cons != NULL);
6771 assert(initialized != NULL);
6772 assert(cutoff != NULL);
6773 assert(*cutoff == FALSE);
6774
6775 SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6776
6777 SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6778 SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6779 SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6780
6781 ncands = 0;
6782 totalenergy = 0;
6783
6785
6786 /* compute the shift which we apply to compute .... latest completion time of all jobs */
6787 if( propest )
6788 shift = 0;
6789 else
6790 {
6791 shift = 0;
6792
6793 /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6794 * earliest start time propagation to handle the latest completion times
6795 */
6796 for( j = 0; j < nvars; ++j )
6797 {
6798 int lct;
6799
6800 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6801 shift = MAX(shift, lct);
6802 }
6803 }
6804
6805 /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6806 * horizon
6807 */
6808 for( j = 0; j < nvars; ++j )
6809 {
6811 SCIP_VAR* var;
6812 int duration;
6813 int leftadjust;
6814 int rightadjust;
6815 int energy;
6816 int est;
6817 int lct;
6818
6819 var = vars[j];
6820 assert(var != NULL);
6821
6822 duration = durations[j];
6823 assert(duration > 0);
6824
6825 leftadjust = 0;
6826 rightadjust = 0;
6827
6829 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6830
6831 /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6832 * effective horizon [hmin,hmax)
6833 */
6834 if( conshdlrdata->useadjustedjobs )
6835 {
6836 if( est < hmin )
6837 {
6838 leftadjust = (hmin - est);
6839 est = hmin;
6840 }
6841 if( lct > hmax )
6842 {
6843 rightadjust = (lct - hmax);
6844 lct = hmax;
6845 }
6846
6847 /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6848 * with the effective time horizon
6849 */
6850 if( duration - leftadjust - rightadjust <= 0 )
6851 continue;
6852 }
6853 else if( est < hmin || lct > hmax )
6854 continue;
6855
6856 energy = demands[j] * (duration - leftadjust - rightadjust);
6857 assert(energy > 0);
6858
6859 totalenergy += energy;
6860
6861 /* flip earliest start time and latest completion time */
6862 if( !propest )
6863 {
6864 SCIPswapInts(&est, &lct);
6865
6866 /* shift earliest start time and latest completion time */
6867 lct = shift - lct;
6868 est = shift - est;
6869 }
6870 else
6871 {
6872 /* shift earliest start time and latest completion time */
6873 lct = lct - shift;
6874 est = est - shift;
6875 }
6876 assert(est < lct);
6877 assert(est >= 0);
6878 assert(lct >= 0);
6879
6880 /* create search node data */
6881 nodedata = &nodedatas[ncands];
6882 nodedataidx[ncands] = ncands;
6883 ++ncands;
6884
6885 /* initialize search node data */
6886 /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6887 nodedata->key = est + j / (2.0 * nvars);
6888 nodedata->var = var;
6889 nodedata->est = est;
6890 nodedata->lct = lct;
6891 nodedata->demand = demands[j];
6892 nodedata->duration = duration;
6893 nodedata->leftadjust = leftadjust;
6894 nodedata->rightadjust = rightadjust;
6895
6896 /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6897 * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6898 * particular time interval [a,b] against the time interval [0,b].
6899 */
6900 nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
6901 nodedata->energytheta = energy;
6902 nodedata->enveloplambda = -1;
6903 nodedata->energylambda = -1;
6904
6905 nodedata->idx = j;
6906 nodedata->intheta = TRUE;
6907 }
6908
6909 nnodedatas = ncands;
6910
6911 /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6912 SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
6913
6914 ninsertcands = 0;
6915
6916 /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6917 * the root envelop detects an overload
6918 */
6919 for( j = 0; j < ncands; ++j )
6920 {
6921 SCIP_BTNODE* leaf;
6922 SCIP_NODEDATA* rootdata;
6923
6924 idx = nodedataidx[j];
6925
6926 /* check if the new job opens a time window which size is so large that it offers more energy than the total
6927 * energy of all candidate jobs. If so we skip that one.
6928 */
6929 if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
6930 {
6931 /* set the earliest start time to minus one to mark that candidate to be not used */
6932 nodedatas[idx].est = -1;
6933 continue;
6934 }
6935
6936 /* create search node */
6937 SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
6938
6939 /* insert new node into the theta set and updete the envelops */
6940 SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
6941 assert(nnodedatas <= 2*nvars);
6942
6943 /* move the inserted candidates together */
6944 leaves[ninsertcands] = leaf;
6945 ninsertcands++;
6946
6947 assert(!SCIPbtIsEmpty(tree));
6948 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6949 assert(rootdata != NULL);
6950
6951 /* check if the theta set envelops exceeds the available capacity */
6952 if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
6953 {
6954 SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
6955 (*cutoff) = TRUE;
6956
6957 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6959
6960 break;
6961 }
6962 }
6963
6964 /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
6965 if( *cutoff )
6966 {
6967 int glbenery;
6968 int est;
6969 int lct;
6970
6971 glbenery = 0;
6972 assert( 0 <= idx );
6973 est = nodedatas[idx].est;
6974 lct = nodedatas[idx].lct;
6975
6976 /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
6977 * which led to an overload
6978 */
6979 for( j = j+1; j < ncands; ++j )
6980 {
6982 int duration;
6983 int glbest;
6984 int glblct;
6985
6986 idx = nodedataidx[j];
6987 nodedata = &nodedatas[idx];
6988 assert(nodedata != NULL);
6989
6990 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6991
6992 /* get latest start time */
6994 glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
6995
6996 /* check if parts of the jobs run with the time window defined by the last inserted job */
6997 if( glbest < est )
6998 duration -= (est - glbest);
6999
7000 if( glblct > lct )
7001 duration -= (glblct - lct);
7002
7003 if( duration > 0 )
7004 {
7005 glbenery += nodedata->demand * duration;
7006
7007 if( explanation != NULL )
7008 explanation[nodedata->idx] = TRUE;
7009 }
7010 }
7011
7012 /* analyze the overload */
7013 SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7014 conshdlrdata->usebdwidening, initialized, explanation) );
7015 }
7016 else if( ninsertcands > 1 && conshdlrdata->efinfer )
7017 {
7018 /* if we have more than one job insterted and edge-finding should be performed we do it */
7019 SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7020 propest, shift, initialized, explanation, nchgbds, cutoff) );
7021 }
7022
7023 /* free theta tree */
7024 SCIPbtFree(&tree);
7025
7026 /* free buffer arrays */
7027 SCIPfreeBufferArray(scip, &leaves);
7028 SCIPfreeBufferArray(scip, &nodedataidx);
7029 SCIPfreeBufferArray(scip, &nodedatas);
7030
7031 return SCIP_OKAY;
7032}
7033
7034/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7035 *
7036 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7037 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7038 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7039 */
7040static
7042 SCIP* scip, /**< SCIP data structure */
7043 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7044 int nvars, /**< number of start time variables (activities) */
7045 SCIP_VAR** vars, /**< array of start time variables */
7046 int* durations, /**< array of durations */
7047 int* demands, /**< array of demands */
7048 int capacity, /**< cumulative capacity */
7049 int hmin, /**< left bound of time axis to be considered (including hmin) */
7050 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7051 SCIP_CONS* cons, /**< constraint which is propagated */
7052 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7053 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7054 int* nchgbds, /**< pointer to store the number of bound changes */
7055 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7056 )
7057{
7058 /* check if a cutoff was already detected */
7059 if( (*cutoff) )
7060 return SCIP_OKAY;
7061
7062 /* check if at least the basic overload checking should be preformed */
7063 if( !conshdlrdata->efcheck )
7064 return SCIP_OKAY;
7065
7066 /* check for overload, which may result in a cutoff */
7067 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7068 cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7069
7070 /* check if a cutoff was detected */
7071 if( (*cutoff) )
7072 return SCIP_OKAY;
7073
7074 /* check if bound should be infer */
7075 if( !conshdlrdata->efinfer )
7076 return SCIP_OKAY;
7077
7078 /* check for overload, which may result in a cutoff */
7079 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7080 cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7081
7082 return SCIP_OKAY;
7083}
7084
7085/** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7086 * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7087 * event points
7088 */
7089static
7091 SCIP* scip, /**< SCIP data structure */
7092 int nvars, /**< number of start time variables (activities) */
7093 SCIP_VAR** vars, /**< array of start time variables */
7094 int* durations, /**< array of durations */
7095 int* demands, /**< array of demands */
7096 int capacity, /**< cumulative capacity */
7097 int hmin, /**< left bound of time axis to be considered (including hmin) */
7098 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7099 SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7100 )
7101{
7102 SCIP_VAR* var;
7103 int* starttimes; /* stores when each job is starting */
7104 int* endtimes; /* stores when each job ends */
7105 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7106 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7107
7108 int lb;
7109 int ub;
7110 int freecapacity; /* remaining capacity */
7111 int curtime; /* point in time which we are just checking */
7112 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7113 int njobs;
7114 int j;
7115
7116 assert(scip != NULL);
7117 assert(redundant != NULL);
7118
7119 (*redundant) = TRUE;
7120
7121 /* if no activities are associated with this cumulative then this constraint is redundant */
7122 if( nvars == 0 )
7123 return SCIP_OKAY;
7124
7125 assert(vars != NULL);
7126
7127 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7128 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7129 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7130 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7131
7132 njobs = 0;
7133
7134 /* assign variables, start and endpoints to arrays */
7135 for( j = 0; j < nvars; ++j )
7136 {
7137 assert(durations[j] > 0);
7138 assert(demands[j] > 0);
7139
7140 var = vars[j];
7141 assert(var != NULL);
7142
7145
7146 /* check if jobs runs completely outside of the effective time horizon */
7147 if( lb >= hmax || ub + durations[j] <= hmin )
7148 continue;
7149
7150 starttimes[njobs] = MAX(lb, hmin);
7151 startindices[njobs] = j;
7152
7153 endtimes[njobs] = MIN(ub + durations[j], hmax);
7154 endindices[njobs] = j;
7155 assert(starttimes[njobs] <= endtimes[njobs]);
7156 njobs++;
7157 }
7158
7159 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7160 SCIPsortIntInt(starttimes, startindices, njobs);
7161 SCIPsortIntInt(endtimes, endindices, njobs);
7162
7163 endindex = 0;
7164 freecapacity = capacity;
7165
7166 /* check each start point of a job whether the capacity is violated or not */
7167 for( j = 0; j < njobs; ++j )
7168 {
7169 curtime = starttimes[j];
7170
7171 /* stop checking, if time point is above hmax */
7172 if( curtime >= hmax )
7173 break;
7174
7175 /* subtract all capacity needed up to this point */
7176 freecapacity -= demands[startindices[j]];
7177 while( j+1 < njobs && starttimes[j+1] == curtime )
7178 {
7179 ++j;
7180 freecapacity -= demands[startindices[j]];
7181 }
7182
7183 /* free all capacity usages of jobs the are no longer running */
7184 while( endtimes[endindex] <= curtime )
7185 {
7186 freecapacity += demands[endindices[endindex]];
7187 ++endindex;
7188 }
7189 assert(freecapacity <= capacity);
7190
7191 /* check freecapacity to be smaller than zero */
7192 if( freecapacity < 0 && curtime >= hmin )
7193 {
7194 (*redundant) = FALSE;
7195 break;
7196 }
7197 } /*lint --e{850}*/
7198
7199 /* free all buffer arrays */
7200 SCIPfreeBufferArray(scip, &endindices);
7201 SCIPfreeBufferArray(scip, &startindices);
7202 SCIPfreeBufferArray(scip, &endtimes);
7203 SCIPfreeBufferArray(scip, &starttimes);
7204
7205 return SCIP_OKAY;
7206}
7207
7208/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7209 * completion time
7210 */
7211static
7213 SCIP* scip, /**< SCIP data structure */
7214 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7215 SCIP_PROFILE* profile, /**< resource profile */
7216 int nvars, /**< number of variables (jobs) */
7217 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7218 int* durations, /**< array containing corresponding durations */
7219 int* demands, /**< array containing corresponding demands */
7220 int capacity, /**< cumulative capacity */
7221 int hmin, /**< left bound of time axis to be considered (including hmin) */
7222 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7223 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7224 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7225 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7226 )
7227{
7228 int v;
7229
7230 /* insert all cores */
7231 for( v = 0; v < nvars; ++v )
7232 {
7233 SCIP_VAR* var;
7234 SCIP_Bool infeasible;
7235 int duration;
7236 int demand;
7237 int begin;
7238 int end;
7239 int est;
7240 int lst;
7241 int pos;
7242
7243 var = vars[v];
7244 assert(var != NULL);
7247
7248 duration = durations[v];
7249 assert(duration > 0);
7250
7251 demand = demands[v];
7252 assert(demand > 0);
7253
7254 /* collect earliest and latest start time */
7257
7258 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7259 if( lst + duration <= hmin || est >= hmax )
7260 continue;
7261
7262 /* compute core interval w.r.t. effective time horizon */
7263 begin = MAX(hmin, lst);
7264 end = MIN(hmax, est + duration);
7265
7266 /* check if a core exists */
7267 if( begin >= end )
7268 continue;
7269
7270 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7271 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7272
7273 /* insert the core into core resource profile (complexity O(log n)) */
7274 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7275
7276 /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7277 if( infeasible )
7278 {
7279 assert(begin <= SCIPprofileGetTime(profile, pos));
7280 assert(end > SCIPprofileGetTime(profile, pos));
7281
7282 /* use conflict analysis to analysis the core insertion which was infeasible */
7283 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7284 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7285
7286 if( explanation != NULL )
7287 explanation[v] = TRUE;
7288
7289 (*cutoff) = TRUE;
7290
7291 /* for the statistic we count the number of times a cutoff was detected due the time-time */
7293
7294 break;
7295 }
7296 }
7297
7298 return SCIP_OKAY;
7299}
7300
7301/** propagate the cumulative condition */
7302static
7304 SCIP* scip, /**< SCIP data structure */
7305 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7306 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7307 int nvars, /**< number of start time variables (activities) */
7308 SCIP_VAR** vars, /**< array of start time variables */
7309 int* durations, /**< array of durations */
7310 int* demands, /**< array of demands */
7311 int capacity, /**< cumulative capacity */
7312 int hmin, /**< left bound of time axis to be considered (including hmin) */
7313 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7314 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7315 int* nchgbds, /**< pointer to store the number of bound changes */
7316 SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7317 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7318 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7319 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7320 )
7321{
7322 SCIP_PROFILE* profile;
7323
7324 SCIP_RETCODE retcode = SCIP_OKAY;
7325
7326 assert(nchgbds != NULL);
7327 assert(initialized != NULL);
7328 assert(cutoff != NULL);
7329 assert(!(*cutoff));
7330
7331 /**@todo avoid always sorting the variable array */
7332
7333 /* check if the constraint is redundant */
7334 SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7335
7336 if( *redundant )
7337 return SCIP_OKAY;
7338
7339 /* create an empty resource profile for profiling the cores of the jobs */
7340 SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7341
7342 /* create core profile (compulsory parts) */
7343 SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7344 initialized, explanation, cutoff), TERMINATE );
7345
7346 /* propagate the job cores until nothing else can be detected */
7347 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7348 {
7349 SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7350 nchgbds, initialized, explanation, cutoff), TERMINATE );
7351 }
7352
7353 /* run edge finding propagator */
7354 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7355 {
7356 SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7357 cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7358 }
7359
7360 /* run time-table edge-finding propagator */
7361 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7362 {
7363 SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7364 nchgbds, initialized, explanation, cutoff), TERMINATE );
7365 }
7366 /* free resource profile */
7367TERMINATE:
7368 SCIPprofileFree(&profile);
7369
7370 return retcode;
7371}
7372
7373/** propagate the cumulative constraint */
7374static
7376 SCIP* scip, /**< SCIP data structure */
7377 SCIP_CONS* cons, /**< constraint to propagate */
7378 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7379 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7380 int* nchgbds, /**< pointer to store the number of bound changes */
7381 int* ndelconss, /**< pointer to store the number of deleted constraints */
7382 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7383 )
7384{
7385 SCIP_CONSDATA* consdata;
7386 SCIP_Bool initialized;
7387 SCIP_Bool redundant;
7388 int oldnchgbds;
7389
7390 assert(scip != NULL);
7391 assert(cons != NULL);
7392
7393 consdata = SCIPconsGetData(cons);
7394 assert(consdata != NULL);
7395
7396 oldnchgbds = *nchgbds;
7397 initialized = FALSE;
7398 redundant = FALSE;
7399
7400 if( SCIPconsIsDeleted(cons) )
7401 {
7402 assert(SCIPinProbing(scip));
7403 return SCIP_OKAY;
7404 }
7405
7406 /* if the constraint marked to be propagated, do nothing */
7407 if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7408 return SCIP_OKAY;
7409
7410 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7411 consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7412 consdata->hmin, consdata->hmax, cons,
7413 nchgbds, &redundant, &initialized, NULL, cutoff) );
7414
7415 if( redundant )
7416 {
7417 SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7418 SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7419
7420 if( !SCIPinProbing(scip) )
7421 {
7423 (*ndelconss)++;
7424 }
7425 }
7426 else
7427 {
7428 if( initialized )
7429 {
7430 /* run conflict analysis since it was initialized */
7431 assert(*cutoff == TRUE);
7432 SCIPdebugMsg(scip, "start conflict analysis\n");
7434 }
7435
7436 /* if successful, reset age of constraint */
7437 if( *cutoff || *nchgbds > oldnchgbds )
7438 {
7440 }
7441 else
7442 {
7443 /* mark the constraint to be propagated */
7444 consdata->propagated = TRUE;
7445 }
7446 }
7447
7448 return SCIP_OKAY;
7449}
7450
7451/** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7452 * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7453 * be realize as domain reduction. Otherwise we do nothing
7454 */
7455static
7457 SCIP* scip, /**< SCIP data structure */
7458 SCIP_VAR** vars, /**< problem variables */
7459 int nvars, /**< number of problem variables */
7460 int probingpos, /**< variable number to apply probing on */
7461 SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7462 SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7463 SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7464 SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7465 SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7466 SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7467 SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7468 SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7469 SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7470 SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7471 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7472 SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7473 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7474 )
7475{
7476 SCIP_VAR* var;
7477 SCIP_Bool tightened;
7478
7479 assert(probingpos >= 0);
7480 assert(probingpos < nvars);
7481 assert(success != NULL);
7482 assert(cutoff != NULL);
7483
7484 var = vars[probingpos];
7485 assert(var != NULL);
7486 assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7487 assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7488 assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7489 assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7490
7491 (*success) = FALSE;
7492
7494 return SCIP_OKAY;
7495
7496 /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7497 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7498 leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7499
7500 if( (*cutoff) )
7501 {
7502 /* note that cutoff may occur if presolving has not been executed fully */
7503 SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7504
7505 if( tightened )
7506 {
7507 (*success) =TRUE;
7508 (*nfixedvars)++;
7509 }
7510
7511 return SCIP_OKAY;
7512 }
7513
7514 /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7515 * presolving has not been executed fully
7516 */
7517 if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7518 {
7519 /* note that cutoff may occur if presolving has not been executed fully */
7520 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7521
7522 if( tightened )
7523 {
7524 (*success) = TRUE;
7525 (*nfixedvars)++;
7526 }
7527
7528 return SCIP_OKAY;
7529 }
7530
7531 /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7532 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7533 rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7534
7535 if( (*cutoff) )
7536 {
7537 /* note that cutoff may occur if presolving has not been executed fully */
7538 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7539
7540 if( tightened )
7541 {
7542 (*success) =TRUE;
7543 (*nfixedvars)++;
7544 }
7545
7546 return SCIP_OKAY;
7547 }
7548
7549 return SCIP_OKAY;
7550}
7551
7552/** is it possible, to round variable down w.r.t. objective function */
7553static
7555 SCIP* scip, /**< SCIP data structure */
7556 SCIP_VAR* var, /**< problem variable */
7557 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7558 )
7559{
7560 SCIP_Real objval;
7561 int scalar;
7562
7563 assert(roundable != NULL);
7564
7565 *roundable = TRUE;
7566
7567 /* a fixed variable can be definition always be safely rounded */
7569 return SCIP_OKAY;
7570
7571 /* in case the variable is not active we need to check the object coefficient of the active variable */
7572 if( !SCIPvarIsActive(var) )
7573 {
7574 SCIP_VAR* actvar;
7575 int constant;
7576
7577 actvar = var;
7578
7579 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7580 assert(scalar != 0);
7581
7582 objval = scalar * SCIPvarGetObj(actvar);
7583 } /*lint !e438*/
7584 else
7585 {
7586 scalar = 1;
7587 objval = SCIPvarGetObj(var);
7588 }
7589
7590 /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7591 * (the transformed problem is always a minimization problem)
7592 *
7593 * @note that we need to check this condition w.r.t. active variable space
7594 */
7595 if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7596 *roundable = FALSE;
7597
7598 return SCIP_OKAY;
7599}
7600
7601/** is it possible, to round variable up w.r.t. objective function */
7602static
7604 SCIP* scip, /**< SCIP data structure */
7605 SCIP_VAR* var, /**< problem variable */
7606 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7607 )
7608{
7609 SCIP_Real objval;
7610 int scalar;
7611
7612 assert(roundable != NULL);
7613
7614 *roundable = TRUE;
7615
7616 /* a fixed variable can be definition always be safely rounded */
7618 return SCIP_OKAY;
7619
7620 /* in case the variable is not active we need to check the object coefficient of the active variable */
7621 if( !SCIPvarIsActive(var) )
7622 {
7623 SCIP_VAR* actvar;
7624 int constant;
7625
7626 actvar = var;
7627
7628 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7629 assert(scalar != 0);
7630
7631 objval = scalar * SCIPvarGetObj(actvar);
7632 } /*lint !e438*/
7633 else
7634 {
7635 scalar = 1;
7636 objval = SCIPvarGetObj(var);
7637 }
7638
7639 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7640 * (the transformed problem is always a minimization problem)
7641 *
7642 * @note that we need to check this condition w.r.t. active variable space
7643 */
7644 if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7645 *roundable = FALSE;
7646
7647 return SCIP_OKAY;
7648}
7649
7650/** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7651 * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7652 * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7653 * the only one locking this variable in the corresponding direction.
7654 */
7655static
7657 SCIP* scip, /**< SCIP data structure */
7658 SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7659 int nconss, /**< number of cumulative constraints */
7660 SCIP_Bool local, /**< use local bounds effective horizon? */
7661 int* alternativelbs, /**< alternative lower bounds */
7662 int* alternativeubs, /**< alternative lower bounds */
7663 int* downlocks, /**< number of constraints with down lock participating by the computation */
7664 int* uplocks /**< number of constraints with up lock participating by the computation */
7665 )
7666{
7667 int nvars;
7668 int c;
7669 int v;
7670
7671 for( c = 0; c < nconss; ++c )
7672 {
7673 SCIP_CONSDATA* consdata;
7674 SCIP_CONS* cons;
7675 SCIP_VAR* var;
7676 int hmin;
7677 int hmax;
7678
7679 cons = conss[c];
7680 assert(cons != NULL);
7681
7682 /* ignore constraints which are already deletet and those which are not check constraints */
7683 if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7684 continue;
7685
7686 consdata = SCIPconsGetData(cons);
7687 assert(consdata != NULL);
7688 assert(consdata->nvars > 1);
7689
7690 /* compute the hmin and hmax */
7691 if( local )
7692 {
7693 SCIP_PROFILE* profile;
7694 SCIP_RETCODE retcode;
7695
7696 /* create empty resource profile with infinity resource capacity */
7697 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7698
7699 /* create worst case resource profile */
7700 retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7701
7702 hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7703 hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7704
7705 /* free worst case profile */
7706 SCIPprofileFree(&profile);
7707
7708 if( retcode != SCIP_OKAY )
7709 return retcode;
7710 }
7711 else
7712 {
7713 hmin = consdata->hmin;
7714 hmax = consdata->hmax;
7715 }
7716
7717 consdata = SCIPconsGetData(cons);
7718 assert(consdata != NULL);
7719
7720 nvars = consdata->nvars;
7721
7722 for( v = 0; v < nvars; ++v )
7723 {
7724 int scalar;
7725 int constant;
7726 int idx;
7727
7728 var = consdata->vars[v];
7729 assert(var != NULL);
7730
7731 /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7733
7734 /* ignore variable locally fixed variables */
7735 if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7736 continue;
7737
7738 SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7739 idx = SCIPvarGetProbindex(var);
7740 assert(idx >= 0);
7741
7742 /* first check lower bound fixing */
7743 if( consdata->downlocks[v] )
7744 {
7745 int ect;
7746 int est;
7747
7748 /* the variable has a down locked */
7749 est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7750 ect = est + consdata->durations[v];
7751
7752 if( ect <= hmin || hmin >= hmax )
7753 downlocks[idx]++;
7754 else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7755 {
7756 alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7757 downlocks[idx]++;
7758 }
7759 }
7760
7761 /* second check upper bound fixing */
7762 if( consdata->uplocks[v] )
7763 {
7764 int duration;
7765 int lct;
7766 int lst;
7767
7768 duration = consdata->durations[v];
7769
7770 /* the variable has a up lock locked */
7771 lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7772 lct = lst + duration;
7773
7774 if( lst >= hmax || hmin >= hmax )
7775 uplocks[idx]++;
7776 else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7777 {
7778 alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7779 uplocks[idx]++;
7780 }
7781 }
7782 }
7783 }
7784
7785 return SCIP_OKAY;
7786}
7787
7788/** apply all fixings which are given by the alternative bounds */
7789static
7791 SCIP* scip, /**< SCIP data structure */
7792 SCIP_VAR** vars, /**< array of active variables */
7793 int nvars, /**< number of active variables */
7794 int* alternativelbs, /**< alternative lower bounds */
7795 int* alternativeubs, /**< alternative lower bounds */
7796 int* downlocks, /**< number of constraints with down lock participating by the computation */
7797 int* uplocks, /**< number of constraints with up lock participating by the computation */
7798 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7799 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7800 )
7801{
7802 SCIP_Real* downimpllbs;
7803 SCIP_Real* downimplubs;
7804 SCIP_Real* downproplbs;
7805 SCIP_Real* downpropubs;
7806 SCIP_Real* upimpllbs;
7807 SCIP_Real* upimplubs;
7808 SCIP_Real* upproplbs;
7809 SCIP_Real* uppropubs;
7810 int v;
7811
7812 /* get temporary memory for storing probing results */
7813 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7814 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7815 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7816 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7817 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7818 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7819 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7820 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7821
7822 for( v = 0; v < nvars; ++v )
7823 {
7824 SCIP_VAR* var;
7825 SCIP_Bool infeasible;
7826 SCIP_Bool fixed;
7827 SCIP_Bool roundable;
7828 int ub;
7829 int lb;
7830
7831 var = vars[v];
7832 assert(var != NULL);
7833
7834 /* ignore variables for which no alternative bounds have been computed */
7835 if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7836 continue;
7837
7840
7841 /* ignore fixed variables */
7842 if( ub - lb <= 0 )
7843 continue;
7844
7845 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7846 {
7847 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7848
7849 if( roundable )
7850 {
7851 if( alternativelbs[v] > ub )
7852 {
7853 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7854 assert(!infeasible);
7855 assert(fixed);
7856
7857 (*nfixedvars)++;
7858
7859 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7860 * constraints
7861 */
7863 }
7864 else
7865 {
7866 SCIP_Bool success;
7867
7868 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7869 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7870 * infeasible we can apply the dual reduction; otherwise we do nothing
7871 */
7872 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7873 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7874 nfixedvars, &success, cutoff) );
7875
7876 if( success )
7877 {
7879 }
7880 }
7881 }
7882 }
7883
7886
7887 /* ignore fixed variables */
7888 if( ub - lb <= 0 )
7889 continue;
7890
7891 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7892 {
7893 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7894
7895 if( roundable )
7896 {
7897 if( alternativeubs[v] < lb )
7898 {
7899 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7900 assert(!infeasible);
7901 assert(fixed);
7902
7903 (*nfixedvars)++;
7904
7905 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7906 * constraints
7907 */
7909 }
7910 else
7911 {
7912 SCIP_Bool success;
7913
7914 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7915 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7916 * infeasible we can apply the dual reduction; otherwise we do nothing
7917 */
7918 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7919 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7920 nfixedvars, &success, cutoff) );
7921
7922 if( success )
7923 {
7925 }
7926 }
7927 }
7928 }
7929 }
7930
7931 /* free temporary memory */
7932 SCIPfreeBufferArray(scip, &uppropubs);
7933 SCIPfreeBufferArray(scip, &upproplbs);
7934 SCIPfreeBufferArray(scip, &upimplubs);
7935 SCIPfreeBufferArray(scip, &upimpllbs);
7936 SCIPfreeBufferArray(scip, &downpropubs);
7937 SCIPfreeBufferArray(scip, &downproplbs);
7938 SCIPfreeBufferArray(scip, &downimplubs);
7939 SCIPfreeBufferArray(scip, &downimpllbs);
7940
7941 return SCIP_OKAY;
7942}
7943
7944/** propagate all constraints together */
7945static
7947 SCIP* scip, /**< SCIP data structure */
7948 SCIP_CONS** conss, /**< all cumulative constraint */
7949 int nconss, /**< number of cumulative constraints */
7950 SCIP_Bool local, /**< use local bounds effective horizon? */
7951 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7952 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7953 SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7954 )
7955{ /*lint --e{715}*/
7956 SCIP_VAR** vars;
7957 int* downlocks;
7958 int* uplocks;
7959 int* alternativelbs;
7960 int* alternativeubs;
7961 int oldnfixedvars;
7962 int nvars;
7963 int v;
7964
7966 return SCIP_OKAY;
7967
7968 nvars = SCIPgetNVars(scip);
7969 oldnfixedvars = *nfixedvars;
7970
7971 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
7972 SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
7973 SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
7974 SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
7975 SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
7976
7977 /* initialize arrays */
7978 for( v = 0; v < nvars; ++v )
7979 {
7980 downlocks[v] = 0;
7981 uplocks[v] = 0;
7982 alternativelbs[v] = INT_MAX;
7983 alternativeubs[v] = INT_MIN;
7984 }
7985
7986 /* compute alternative bounds */
7987 SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
7988
7989 /* apply fixing which result of the alternative bounds directly */
7990 SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
7991 nfixedvars, cutoff) );
7992
7993 if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
7994 {
7995 SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
7996 }
7997
7998 /* free all buffers */
7999 SCIPfreeBufferArray(scip, &alternativeubs);
8000 SCIPfreeBufferArray(scip, &alternativelbs);
8001 SCIPfreeBufferArray(scip, &uplocks);
8002 SCIPfreeBufferArray(scip, &downlocks);
8003 SCIPfreeBufferArray(scip, &vars);
8004
8005 return SCIP_OKAY;
8006}
8007
8008/**@} */
8009
8010/**@name Linear relaxations
8011 *
8012 * @{
8013 */
8014
8015/** creates covering cuts for jobs violating resource constraints */
8016static
8018 SCIP* scip, /**< SCIP data structure */
8019 SCIP_CONS* cons, /**< constraint to be checked */
8020 int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8021 int time /**< at this point in time covering constraints are valid */
8022 )
8023{
8024 SCIP_CONSDATA* consdata;
8025 SCIP_ROW* row;
8026 int* flexibleids;
8027 int* demands;
8028
8029 char rowname[SCIP_MAXSTRLEN];
8030
8031 int remainingcap;
8032 int smallcoversize; /* size of a small cover */
8033 int bigcoversize; /* size of a big cover */
8034 int nvars;
8035
8036 int nflexible;
8037 int sumdemand; /* demand of all jobs up to a certain index */
8038 int j;
8039
8040 assert(cons != NULL);
8041
8042 /* get constraint data structure */
8043 consdata = SCIPconsGetData(cons);
8044 assert(consdata != NULL );
8045
8046 nvars = consdata->nvars;
8047
8048 /* sort jobs according to demands */
8049 SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8050 SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8051
8052 nflexible = 0;
8053 remainingcap = consdata->capacity;
8054
8055 /* get all jobs intersecting point 'time' with their bounds */
8056 for( j = 0; j < nvars; ++j )
8057 {
8058 int ub;
8059
8060 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8061
8062 /* only add jobs to array if they intersect with point 'time' */
8063 if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8064 {
8065 /* if job is fixed, capacity has to be decreased */
8066 if( startvalues[j] == ub )
8067 {
8068 remainingcap -= consdata->demands[j];
8069 }
8070 else
8071 {
8072 demands[nflexible] = consdata->demands[j];
8073 flexibleids[nflexible] = j;
8074 ++nflexible;
8075 }
8076 }
8077 }
8078 assert(remainingcap >= 0);
8079
8080 /* sort demands and job ids */
8081 SCIPsortIntInt(demands, flexibleids, nflexible);
8082
8083 /*
8084 * version 1:
8085 * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8086 * erzeuge cover constraint
8087 *
8088 */
8089
8090 /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8091 sumdemand = 0;
8092 j = 0;
8093
8094 while( j < nflexible && sumdemand <= remainingcap )
8095 {
8096 sumdemand += demands[j];
8097 j++;
8098 }
8099
8100 /* j jobs form a conflict, set coversize to 'j - 1' */
8101 bigcoversize = j-1;
8102 assert(sumdemand > remainingcap);
8103 assert(bigcoversize < nflexible);
8104
8105 /* - create a row for all jobs and their binary variables.
8106 * - at most coversize many binary variables of jobs can be set to one
8107 */
8108
8109 /* construct row name */
8110 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8111 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8112 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8114
8115 for( j = 0; j < nflexible; ++j )
8116 {
8117 SCIP_VAR** binvars;
8118 SCIP_Real* vals;
8119 int nbinvars;
8120 int idx;
8121 int start;
8122 int end;
8123 int lb;
8124 int ub;
8125 int b;
8126
8127 idx = flexibleids[j];
8128
8129 /* get and add binvars into var array */
8130 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8131 assert(nbinvars != 0);
8132
8133 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8134 assert(vals != NULL);
8135
8136 lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8137 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8138
8139 /* compute start and finishing time */
8140 start = time - consdata->durations[idx] + 1;
8141 end = MIN(time, ub);
8142
8143 /* add all neccessary binary variables */
8144 for( b = 0; b < nbinvars; ++b )
8145 {
8146 if( vals[b] < start || vals[b] < lb )
8147 continue;
8148
8149 if( vals[b] > end )
8150 break;
8151
8152 assert(binvars[b] != NULL);
8153 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8154 }
8155 }
8156
8157 /* insert and release row */
8159
8160 if( consdata->bcoverrowssize == 0 )
8161 {
8162 consdata->bcoverrowssize = 10;
8163 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8164 }
8165 if( consdata->nbcoverrows == consdata->bcoverrowssize )
8166 {
8167 consdata->bcoverrowssize *= 2;
8168 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8169 }
8170
8171 consdata->bcoverrows[consdata->nbcoverrows] = row;
8172 consdata->nbcoverrows++;
8173
8174 /*
8175 * version 2:
8176 * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8177 * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8178 */
8179 /* find maximum number of jobs that can run in parallel (= coversize -1) */
8180 sumdemand = 0;
8181 j = nflexible -1;
8182 while( sumdemand <= remainingcap )
8183 {
8184 assert(j >= 0);
8185 sumdemand += demands[j];
8186 j--;
8187 }
8188
8189 smallcoversize = nflexible - (j + 1) - 1;
8190 while( j > 0 && demands[j] == demands[nflexible-1] )
8191 --j;
8192
8193 assert(smallcoversize < nflexible);
8194
8195 if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8196 {
8197 /* construct row name */
8198 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8199 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8200 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8202
8203 /* filter binary variables for each unfixed job */
8204 for( j = j + 1; j < nflexible; ++j )
8205 {
8206 SCIP_VAR** binvars;
8207 SCIP_Real* vals;
8208 int nbinvars;
8209 int idx;
8210 int start;
8211 int end;
8212 int lb;
8213 int ub;
8214 int b;
8215
8216 idx = flexibleids[j];
8217
8218 /* get and add binvars into var array */
8219 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8220 assert(nbinvars != 0);
8221
8222 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8223 assert(vals != NULL);
8224
8225 lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8226 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8227
8228 /* compute start and finishing time */
8229 start = time - consdata->durations[idx] + 1;
8230 end = MIN(time, ub);
8231
8232 /* add all neccessary binary variables */
8233 for( b = 0; b < nbinvars; ++b )
8234 {
8235 if( vals[b] < start || vals[b] < lb )
8236 continue;
8237
8238 if( vals[b] > end )
8239 break;
8240
8241 assert(binvars[b] != NULL);
8242 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8243 }
8244 }
8245
8246 /* insert and release row */
8248 if( consdata->scoverrowssize == 0 )
8249 {
8250 consdata->scoverrowssize = 10;
8251 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8252 }
8253 if( consdata->nscoverrows == consdata->scoverrowssize )
8254 {
8255 consdata->scoverrowssize *= 2;
8256 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8257 }
8258
8259 consdata->scoverrows[consdata->nscoverrows] = row;
8260 consdata->nscoverrows++;
8261 }
8262
8263 /* free buffer arrays */
8264 SCIPfreeBufferArray(scip, &flexibleids);
8265 SCIPfreeBufferArray(scip, &demands);
8266
8267 return SCIP_OKAY;
8268}
8269
8270/** method to construct cover cuts for all points in time */
8271static
8273 SCIP* scip, /**< SCIP data structure */
8274 SCIP_CONS* cons /**< constraint to be separated */
8275 )
8276{
8277 SCIP_CONSDATA* consdata;
8278
8279 int* startvalues; /* stores when each job is starting */
8280 int* endvalues; /* stores when each job ends */
8281 int* startvaluessorted; /* stores when each job is starting */
8282 int* endvaluessorted; /* stores when each job ends */
8283 int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8284 int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8285
8286 int nvars; /* number of jobs for this constraint */
8287 int freecapacity; /* remaining capacity */
8288 int curtime; /* point in time which we are just checking */
8289 int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8290
8291 int hmin;
8292 int hmax;
8293
8294 int j;
8295 int t;
8296
8297 assert(scip != NULL);
8298 assert(cons != NULL);
8299
8300 consdata = SCIPconsGetData(cons);
8301 assert(consdata != NULL);
8302
8303 /* if no activities are associated with this resource then this constraint is redundant */
8304 if( consdata->vars == NULL )
8305 return SCIP_OKAY;
8306
8307 nvars = consdata->nvars;
8308 hmin = consdata->hmin;
8309 hmax = consdata->hmax;
8310
8311 SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8312 SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8313 SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8314 SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8315 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8316 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8317
8318 /* assign start and endpoints to arrays */
8319 for ( j = 0; j < nvars; ++j )
8320 {
8321 startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8322 startvaluessorted[j] = startvalues[j];
8323
8324 endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8325 endvaluessorted[j] = endvalues[j];
8326
8327 startindices[j] = j;
8328 endindices[j] = j;
8329 }
8330
8331 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8332 * (and sort the indices in the same way) */
8333 SCIPsortIntInt(startvaluessorted, startindices, nvars);
8334 SCIPsortIntInt(endvaluessorted, endindices, nvars);
8335
8336 endidx = 0;
8337 freecapacity = consdata->capacity;
8338
8339 /* check each startpoint of a job whether the capacity is kept or not */
8340 for( j = 0; j < nvars; ++j )
8341 {
8342 curtime = startvaluessorted[j];
8343 if( curtime >= hmax )
8344 break;
8345
8346 /* subtract all capacity needed up to this point */
8347 freecapacity -= consdata->demands[startindices[j]];
8348
8349 while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8350 {
8351 ++j;
8352 freecapacity -= consdata->demands[startindices[j]];
8353 }
8354
8355 /* free all capacity usages of jobs the are no longer running */
8356 while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8357 {
8358 freecapacity += consdata->demands[endindices[endidx]];
8359 ++endidx;
8360 }
8361
8362 assert(freecapacity <= consdata->capacity);
8363 assert(endidx <= nvars);
8364
8365 /* --> endindex - points to the next job which will finish
8366 * j - points to the last job that has been released
8367 */
8368
8369 /* check freecapacity to be smaller than zero
8370 * then we will add cover constraints to the MIP
8371 */
8372 if( freecapacity < 0 && curtime >= hmin )
8373 {
8374 int nextprofilechange;
8375
8376 /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8377 if( j < nvars-1 )
8378 nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8379 else
8380 nextprofilechange = endvaluessorted[endidx];
8381
8382 nextprofilechange = MIN(nextprofilechange, hmax);
8383
8384 for( t = curtime; t < nextprofilechange; ++t )
8385 {
8386 SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8387
8388 /* create covering constraint */
8389 SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8390 }
8391 } /* end if freecapacity > 0 */
8392 } /*lint --e{850}*/
8393
8394 consdata->covercuts = TRUE;
8395
8396 /* free all buffer arrays */
8397 SCIPfreeBufferArray(scip, &endindices);
8398 SCIPfreeBufferArray(scip, &startindices);
8399 SCIPfreeBufferArray(scip, &endvaluessorted);
8400 SCIPfreeBufferArray(scip, &startvaluessorted);
8401 SCIPfreeBufferArray(scip, &endvalues);
8402 SCIPfreeBufferArray(scip, &startvalues);
8403
8404 return SCIP_OKAY;
8405}
8406
8407/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8408 * constraint
8409 */
8410static
8412 SCIP* scip, /**< SCIP data structure */
8413 SCIP_CONS* cons, /**< constraint to be checked */
8414 int* startindices, /**< permutation with rspect to the start times */
8415 int curtime, /**< current point in time */
8416 int nstarted, /**< number of jobs that start before the curtime or at curtime */
8417 int nfinished, /**< number of jobs that finished before curtime or at curtime */
8418 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8419 )
8420{
8421 SCIP_CONSDATA* consdata;
8422 SCIP_VAR** binvars;
8423 int* coefs;
8424 int nbinvars;
8425 char name[SCIP_MAXSTRLEN];
8426 int capacity;
8427 int b;
8428
8429 assert(nstarted > nfinished);
8430
8431 consdata = SCIPconsGetData(cons);
8432 assert(consdata != NULL);
8433 assert(consdata->nvars > 0);
8434
8435 capacity = consdata->capacity;
8436 assert(capacity > 0);
8437
8438 nbinvars = 0;
8439 SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8440
8441 /* construct row name */
8442 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8443
8444 if( cutsasconss )
8445 {
8446 SCIP_CONS* lincons;
8447
8448 /* create knapsack constraint for the given time point */
8449 SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8451
8452 for( b = 0; b < nbinvars; ++b )
8453 {
8454 SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8455 }
8456
8457 /* add and release the new constraint */
8458 SCIP_CALL( SCIPaddCons(scip, lincons) );
8459 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8460 }
8461 else
8462 {
8463 SCIP_ROW* row;
8464
8465 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8467
8468 for( b = 0; b < nbinvars; ++b )
8469 {
8470 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8471 }
8472
8475
8476 if( consdata->demandrowssize == 0 )
8477 {
8478 consdata->demandrowssize = 10;
8479 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8480 }
8481 if( consdata->ndemandrows == consdata->demandrowssize )
8482 {
8483 consdata->demandrowssize *= 2;
8484 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8485 }
8486
8487 consdata->demandrows[consdata->ndemandrows] = row;
8488 consdata->ndemandrows++;
8489 }
8490
8491 SCIPfreeBufferArrayNull(scip, &binvars);
8493
8494 return SCIP_OKAY;
8495}
8496
8497/** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8498 * row
8499 */
8500static
8502 SCIP* scip, /**< SCIP data structure */
8503 SCIP_CONS* cons, /**< constraint to be checked */
8504 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8505 )
8506{
8507 SCIP_CONSDATA* consdata;
8508
8509 int* starttimes; /* stores when each job is starting */
8510 int* endtimes; /* stores when each job ends */
8511 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8512 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8513
8514 int nvars; /* number of activities for this constraint */
8515 int freecapacity; /* remaining capacity */
8516 int curtime; /* point in time which we are just checking */
8517 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8518
8519 int hmin;
8520 int hmax;
8521
8522 int j;
8523
8524 assert(scip != NULL);
8525 assert(cons != NULL);
8526
8527 consdata = SCIPconsGetData(cons);
8528 assert(consdata != NULL);
8529
8530 nvars = consdata->nvars;
8531
8532 /* if no activities are associated with this cumulative then this constraint is redundant */
8533 if( nvars == 0 )
8534 return SCIP_OKAY;
8535
8536 assert(consdata->vars != NULL);
8537
8538 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8539 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8540 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8541 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8542
8543 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8544 SCIPconsGetName(cons), nvars);
8545
8546 /* create event point arrays */
8547 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8548 starttimes, endtimes, startindices, endindices, FALSE);
8549
8550 endindex = 0;
8551 freecapacity = consdata->capacity;
8552 hmin = consdata->hmin;
8553 hmax = consdata->hmax;
8554
8555 /* check each startpoint of a job whether the capacity is kept or not */
8556 for( j = 0; j < nvars; ++j )
8557 {
8558 curtime = starttimes[j];
8559 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8560
8561 if( curtime >= hmax )
8562 break;
8563
8564 /* remove the capacity requirments for all job which start at the curtime */
8565 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8566
8567 /* add the capacity requirments for all job which end at the curtime */
8568 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8569
8570 assert(freecapacity <= consdata->capacity);
8571 assert(endindex <= nvars);
8572
8573 /* endindex - points to the next job which will finish */
8574 /* j - points to the last job that has been released */
8575
8576 /* if free capacity is smaller than zero, then add rows to the LP */
8577 if( freecapacity < 0 && curtime >= hmin )
8578 {
8579 int nextstarttime;
8580 int t;
8581
8582 /* step forward until next job is released and see whether capacity constraint is met or not */
8583 if( j < nvars-1 )
8584 nextstarttime = starttimes[j+1];
8585 else
8586 nextstarttime = endtimes[nvars-1];
8587
8588 nextstarttime = MIN(nextstarttime, hmax);
8589
8590 /* create capacity restriction row for current event point */
8591 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8592
8593 /* create for all points in time between the current event point and next start event point a row if the free
8594 * capacity is still smaller than zero */
8595 for( t = curtime+1 ; t < nextstarttime; ++t )
8596 {
8597 /* add the capacity requirments for all job which end at the curtime */
8598 addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8599
8600 if( freecapacity < 0 )
8601 {
8602 /* add constraint */
8603 SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8604
8605 /* create capacity restriction row */
8606 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8607 }
8608 else
8609 break;
8610 }
8611 }
8612 } /*lint --e{850}*/
8613
8614 /* free all buffer arrays */
8615 SCIPfreeBufferArray(scip, &endindices);
8616 SCIPfreeBufferArray(scip, &startindices);
8617 SCIPfreeBufferArray(scip, &endtimes);
8618 SCIPfreeBufferArray(scip, &starttimes);
8619
8620 return SCIP_OKAY;
8621}
8622
8623/** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8624 * capacity is larger than the capacity of the cumulative constraint
8625 * - for each necessary point in time:
8626 *
8627 * sum_j sum_t demand_j * x_{j,t} <= capacity
8628 *
8629 * where x(j,t) is the binary variables of job j at time t
8630 */
8631static
8633 SCIP* scip, /**< SCIP data structure */
8634 SCIP_CONS* cons, /**< cumulative constraint */
8635 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8636 )
8637{
8638 SCIP_CONSDATA* consdata;
8639
8640 consdata = SCIPconsGetData(cons);
8641 assert(consdata != NULL);
8642 assert(consdata->demandrows == NULL);
8643 assert(consdata->ndemandrows == 0);
8644
8645 /* collect the linking constraints */
8646 if( consdata->linkingconss == NULL )
8647 {
8649 }
8650
8651 SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8652
8653 /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8654 if( cutsasconss )
8655 {
8656 if( SCIPconsIsInitial(cons) )
8657 {
8659 }
8660 if( SCIPconsIsSeparated(cons) )
8661 {
8663 }
8664 if( SCIPconsIsEnforced(cons) )
8665 {
8667 }
8668 }
8669
8670 return SCIP_OKAY;
8671}
8672
8673/** adds linear relaxation of cumulative constraint to the LP */
8674static
8676 SCIP* scip, /**< SCIP data structure */
8677 SCIP_CONS* cons, /**< cumulative constraint */
8678 SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8679 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8680 )
8681{
8682 SCIP_CONSDATA* consdata;
8683 int r;
8684
8685 consdata = SCIPconsGetData(cons);
8686 assert(consdata != NULL);
8687
8688 if( consdata->demandrows == NULL )
8689 {
8690 assert(consdata->ndemandrows == 0);
8691
8692 SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8693
8694 return SCIP_OKAY;
8695 }
8696
8697 for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8698 {
8699 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8700 {
8701 assert(consdata->demandrows[r] != NULL);
8702 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8703 }
8704 }
8705
8706 return SCIP_OKAY;
8707}
8708
8709/** checks constraint for violation, and adds it as a cut if possible */
8710static
8712 SCIP* scip, /**< SCIP data structure */
8713 SCIP_CONS* cons, /**< cumulative constraint to be separated */
8714 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8715 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8716 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8717 )
8718{ /*lint --e{715}*/
8719 SCIP_CONSDATA* consdata;
8720 int ncuts;
8721 int r;
8722
8723 assert(scip != NULL);
8724 assert(cons != NULL);
8725 assert(separated != NULL);
8726 assert(cutoff != NULL);
8727
8728 *separated = FALSE;
8729 *cutoff = FALSE;
8730
8731 consdata = SCIPconsGetData(cons);
8732 assert(consdata != NULL);
8733
8734 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8735
8736 if( consdata->demandrows == NULL )
8737 {
8738 assert(consdata->ndemandrows == 0);
8739
8741
8742 return SCIP_OKAY;
8743 }
8744
8745 ncuts = 0;
8746
8747 /* check each row that is not contained in LP */
8748 for( r = 0; r < consdata->ndemandrows; ++r )
8749 {
8750 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8751 {
8752 SCIP_Real feasibility;
8753
8754 if( sol != NULL )
8755 feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8756 else
8757 feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8758
8759 if( SCIPisFeasNegative(scip, feasibility) )
8760 {
8761 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8762 if ( *cutoff )
8763 {
8765 return SCIP_OKAY;
8766 }
8767 *separated = TRUE;
8768 ncuts++;
8769 }
8770 }
8771 }
8772
8773 if( ncuts > 0 )
8774 {
8775 SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8776
8777 /* if successful, reset age of constraint */
8779 (*separated) = TRUE;
8780 }
8781
8782 return SCIP_OKAY;
8783}
8784
8785/** checks constraint for violation, and adds it as a cut if possible */
8786static
8788 SCIP* scip, /**< SCIP data structure */
8789 SCIP_CONS* cons, /**< logic or constraint to be separated */
8790 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8791 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8792 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8793 )
8794{
8795 SCIP_CONSDATA* consdata;
8796 SCIP_ROW* row;
8797 SCIP_Real minfeasibility;
8798 int r;
8799
8800 assert(scip != NULL);
8801 assert(cons != NULL);
8802 assert(separated != NULL);
8803 assert(cutoff != NULL);
8804
8805 *separated = FALSE;
8806 *cutoff = FALSE;
8807
8808 consdata = SCIPconsGetData(cons);
8809 assert(consdata != NULL);
8810
8811 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8812
8813 /* collect the linking constraints */
8814 if( consdata->linkingconss == NULL )
8815 {
8817 }
8818
8819 if( !consdata->covercuts )
8820 {
8821 SCIP_CALL( createCoverCuts(scip, cons) );
8822 }
8823
8824 row = NULL;
8825 minfeasibility = SCIPinfinity(scip);
8826
8827 /* check each row of small covers that is not contained in LP */
8828 for( r = 0; r < consdata->nscoverrows; ++r )
8829 {
8830 if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8831 {
8832 SCIP_Real feasibility;
8833
8834 assert(consdata->scoverrows[r] != NULL);
8835 if( sol != NULL )
8836 feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8837 else
8838 feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8839
8840 if( minfeasibility > feasibility )
8841 {
8842 minfeasibility = feasibility;
8843 row = consdata->scoverrows[r];
8844 }
8845 }
8846 }
8847
8848 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8849
8850 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8851 {
8852 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8853 SCIPconsGetName(cons), minfeasibility);
8854
8855 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8857 if ( *cutoff )
8858 return SCIP_OKAY;
8859 (*separated) = TRUE;
8860 }
8861
8862 minfeasibility = SCIPinfinity(scip);
8863 row = NULL;
8864
8865 /* check each row of small covers that is not contained in LP */
8866 for( r = 0; r < consdata->nbcoverrows; ++r )
8867 {
8868 if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8869 {
8870 SCIP_Real feasibility;
8871
8872 assert(consdata->bcoverrows[r] != NULL);
8873 if( sol != NULL )
8874 feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8875 else
8876 feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8877
8878 if( minfeasibility > feasibility )
8879 {
8880 minfeasibility = feasibility;
8881 row = consdata->bcoverrows[r];
8882 }
8883 }
8884 }
8885
8886 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8887
8888 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8889 {
8890 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8891 SCIPconsGetName(cons), minfeasibility);
8892
8893 assert(row != NULL);
8894 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8896 if ( *cutoff )
8897 return SCIP_OKAY;
8898 (*separated) = TRUE;
8899 }
8900
8901 return SCIP_OKAY;
8902}
8903
8904/** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8905static
8907 SCIP* scip, /**< SCIP data structure */
8908 SCIP_CONS* cons, /**< constraint to be checked */
8909 int* startindices, /**< permutation with rspect to the start times */
8910 int curtime, /**< current point in time */
8911 int nstarted, /**< number of jobs that start before the curtime or at curtime */
8912 int nfinished, /**< number of jobs that finished before curtime or at curtime */
8913 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
8914 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
8915 )
8916{
8917 SCIP_CONSDATA* consdata;
8918 char name[SCIP_MAXSTRLEN];
8919 int lhs; /* left hand side of constraint */
8920
8921 SCIP_VAR** activevars;
8922 SCIP_ROW* row;
8923
8924 int v;
8925
8926 assert(nstarted > nfinished);
8927
8928 consdata = SCIPconsGetData(cons);
8929 assert(consdata != NULL);
8930 assert(consdata->nvars > 0);
8931
8932 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8933
8934 SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8935
8936 if( lower )
8937 {
8938 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8939
8940 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
8941 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8942 }
8943 else
8944 {
8945 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8946 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8947 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8948 }
8949
8951
8952 for( v = 0; v < nstarted - nfinished; ++v )
8953 {
8954 SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
8955 }
8956
8959
8960 SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
8961
8962 SCIP_CALL( SCIPreleaseRow(scip, &row) );
8963
8964 /* free buffers */
8965 SCIPfreeBufferArrayNull(scip, &activevars);
8966
8967 return SCIP_OKAY;
8968}
8969
8970/** checks constraint for violation, and adds it as a cut if possible */
8971static
8973 SCIP* scip, /**< SCIP data structure */
8974 SCIP_CONS* cons, /**< cumulative constraint to be separated */
8975 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8976 SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
8977 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8978 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
8979 )
8980{
8981 SCIP_CONSDATA* consdata;
8982
8983 int* starttimes; /* stores when each job is starting */
8984 int* endtimes; /* stores when each job ends */
8985 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8986 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8987
8988 int nvars; /* number of activities for this constraint */
8989 int freecapacity; /* remaining capacity */
8990 int curtime; /* point in time which we are just checking */
8991 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8992
8993 int hmin;
8994 int hmax;
8995 int j;
8996
8997 assert(scip != NULL);
8998 assert(cons != NULL);
8999
9000 consdata = SCIPconsGetData(cons);
9001 assert(consdata != NULL);
9002
9003 nvars = consdata->nvars;
9004
9005 /* if no activities are associated with this cumulative then this constraint is redundant */
9006 if( nvars <= 1 )
9007 return SCIP_OKAY;
9008
9009 assert(consdata->vars != NULL);
9010
9011 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9012 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9013 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9014 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9015
9016 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9017 SCIPconsGetName(cons), nvars);
9018
9019 /* create event point arrays */
9020 createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9021
9022 /* now nvars might be smaller than before! */
9023
9024 endindex = 0;
9025 freecapacity = consdata->capacity;
9026 hmin = consdata->hmin;
9027 hmax = consdata->hmax;
9028
9029 /* check each startpoint of a job whether the capacity is kept or not */
9030 for( j = 0; j < nvars && !(*cutoff); ++j )
9031 {
9032 curtime = starttimes[j];
9033
9034 if( curtime >= hmax )
9035 break;
9036
9037 /* remove the capacity requirements for all job which start at the curtime */
9038 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9039
9040 /* add the capacity requirments for all job which end at the curtime */
9041 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9042
9043 assert(freecapacity <= consdata->capacity);
9044 assert(endindex <= nvars);
9045
9046 /* endindex - points to the next job which will finish */
9047 /* j - points to the last job that has been released */
9048
9049 /* if free capacity is smaller than zero, then add rows to the LP */
9050 if( freecapacity < 0 && curtime >= hmin)
9051 {
9052 /* create capacity restriction row for current event point */
9053 SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9054 *separated = TRUE;
9055 }
9056 } /*lint --e{850}*/
9057
9058 /* free all buffer arrays */
9059 SCIPfreeBufferArray(scip, &endindices);
9060 SCIPfreeBufferArray(scip, &startindices);
9061 SCIPfreeBufferArray(scip, &endtimes);
9062 SCIPfreeBufferArray(scip, &starttimes);
9063
9064 return SCIP_OKAY;
9065}
9066
9067/**@} */
9068
9069
9070/**@name Presolving
9071 *
9072 * @{
9073 */
9074
9075#ifndef NDEBUG
9076/** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9077 * correct
9078 */
9079static
9081 SCIP* scip, /**< SCIP data structure */
9082 SCIP_CONS* cons /**< constraint to be checked */
9083 )
9084{
9085 SCIP_CONSDATA* consdata;
9086 int capacity;
9087 int nvars;
9088 int j;
9089
9090 assert(scip != NULL);
9091 assert(cons != NULL);
9092
9093 consdata = SCIPconsGetData(cons);
9094 assert(consdata != NULL);
9095
9096 nvars = consdata->nvars;
9097
9098 /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9099 if( nvars <= 1 )
9100 return TRUE;
9101
9102 assert(consdata->vars != NULL);
9103 capacity = consdata->capacity;
9104
9105 /* check each activity: if demand is larger than capacity the problem is infeasible */
9106 for ( j = 0; j < nvars; ++j )
9107 {
9108 if( consdata->demands[j] > capacity )
9109 return FALSE;
9110 }
9111
9112 return TRUE;
9113}
9114#endif
9115
9116/** delete constraint if it consists of at most one job
9117 *
9118 * @todo this method needs to be adjusted w.r.t. effective horizon
9119 */
9120static
9122 SCIP* scip, /**< SCIP data structure */
9123 SCIP_CONS* cons, /**< constraint to propagate */
9124 int* ndelconss, /**< pointer to store the number of deleted constraints */
9125 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9126 )
9127{
9128 SCIP_CONSDATA* consdata;
9129
9130 assert(scip != NULL);
9131 assert(cons != NULL);
9132
9133 consdata = SCIPconsGetData(cons);
9134 assert(consdata != NULL);
9135
9136 if( consdata->nvars == 0 )
9137 {
9138 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9139
9140 SCIP_CALL( SCIPdelCons(scip, cons) );
9141 (*ndelconss)++;
9142 }
9143 else if( consdata->nvars == 1 )
9144 {
9145 if( consdata->demands[0] > consdata->capacity )
9146 (*cutoff) = TRUE;
9147 else
9148 {
9149 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9150
9151 SCIP_CALL( SCIPdelCons(scip, cons) );
9152 (*ndelconss)++;
9153 }
9154 }
9155
9156 return SCIP_OKAY;
9157}
9158
9159/** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9160 * this is done in the SCIP_DECL_CONSINITPRE() callback
9161 */
9162static
9164 SCIP* scip, /**< SCIP data structure */
9165 SCIP_CONS* cons /**< constraint to propagate */
9166 )
9167{
9168 SCIP_CONSDATA* consdata;
9169 SCIP_VAR* var;
9170 int demand;
9171 int duration;
9172 int hmin;
9173 int hmax;
9174 int est;
9175 int lct;
9176 int j;
9177
9178 assert(scip != NULL);
9179 assert(cons != NULL);
9180
9181 consdata = SCIPconsGetData(cons);
9182 assert(consdata != NULL);
9183
9184 hmin = consdata->hmin;
9185 hmax = consdata->hmax;
9186
9187 SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9188 SCIPconsGetName(cons), hmin, hmax);
9189
9190 for( j = consdata->nvars-1; j >= 0; --j )
9191 {
9192 var = consdata->vars[j];
9193 demand = consdata->demands[j];
9194 duration = consdata->durations[j];
9195
9196 /* earliest completion time (ect) and latest start time (lst) */
9198 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9199
9200 if( demand == 0 || duration == 0 )
9201 {
9202 /* jobs with zero demand or zero duration can be removed */
9203 SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9204 SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9205
9206 /* remove variable form constraint */
9207 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9208 }
9209 else if( est >= hmax || lct <= hmin )
9210 {
9211 SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9212 SCIPvarGetName(var), est, lct - duration, duration);
9213
9214 /* delete variable at the given position */
9215 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9216
9217 /* for the statistic we count the number of jobs which are irrelevant */
9219 }
9220 }
9221
9222 return SCIP_OKAY;
9223}
9224
9225/** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9226static
9228 SCIP* scip, /**< SCIP data structure */
9229 SCIP_CONSDATA* consdata, /**< constraint data */
9230 int pos, /**< position of job in the consdata */
9231 int* nchgbds, /**< pointer to store the number of changed bounds */
9232 int* naddconss, /**< pointer to store the number of added constraints */
9233 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9234 )
9235{
9236 SCIP_VAR* var;
9237 SCIP_Bool tightened;
9238 int duration;
9239 int ect;
9240 int lst;
9241
9242 assert(scip != NULL);
9243
9244 /* zero energy jobs should be removed already */
9245 assert(consdata->durations[pos] > 0);
9246 assert(consdata->demands[pos] > 0);
9247
9248 var = consdata->vars[pos];
9249 assert(var != NULL);
9250 duration = consdata->durations[pos];
9251
9252 /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9253 SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9254 SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9255
9256 /* earliest completion time (ect) and latest start time (lst) */
9257 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9259
9260 /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9261 if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9262 return SCIP_OKAY;
9263
9264 if( ect > consdata->hmin && lst < consdata->hmax )
9265 {
9266 /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9267 *cutoff = TRUE;
9268 }
9269 else if( lst < consdata->hmax )
9270 {
9271 /* move the latest start time of this job in such a way that it finishes before or at hmin */
9272 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9273 assert(tightened);
9274 assert(!(*cutoff));
9275 (*nchgbds)++;
9276 }
9277 else if( ect > consdata->hmin )
9278 {
9279 /* move the earliest start time of this job in such a way that it starts after or at hmax */
9280 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9281 assert(tightened);
9282 assert(!(*cutoff));
9283 (*nchgbds)++;
9284 }
9285 else
9286 {
9287 /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9288 * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9289 *
9290 * (var <= hmin - duration) /\ (var >= hmax)
9291 */
9292 SCIP_CONS* cons;
9293
9294 SCIP_VAR* vartuple[2];
9295 SCIP_BOUNDTYPE boundtypetuple[2];
9296 SCIP_Real boundtuple[2];
9297
9298 char name[SCIP_MAXSTRLEN];
9299 int leftbound;
9300 int rightbound;
9301
9302 leftbound = consdata->hmin - duration;
9303 rightbound = consdata->hmax;
9304
9305 /* allocate temporary memory for arrays */
9306 vartuple[0] = var;
9307 vartuple[1] = var;
9308 boundtuple[0] = (SCIP_Real)leftbound;
9309 boundtuple[1] = (SCIP_Real)rightbound;
9310 boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9311 boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9312
9313 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9314 SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9315
9316 /* create and add bounddisjunction constraint */
9317 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9318 TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9319
9321
9322 /* add and release the new constraint */
9323 SCIP_CALL( SCIPaddCons(scip, cons) );
9324 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9325 (*naddconss)++;
9326 }
9327
9328 return SCIP_OKAY;
9329}
9330
9331/** try to removed over sizeed jobs (the demand is larger than the capacity) */
9332static
9334 SCIP* scip, /**< SCIP data structure */
9335 SCIP_CONS* cons, /**< constraint */
9336 int* nchgbds, /**< pointer to store the number of changed bounds */
9337 int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9338 int* naddconss, /**< pointer to store the number of added constraints */
9339 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9340 )
9341{
9342 SCIP_CONSDATA* consdata;
9343 int capacity;
9344 int j;
9345
9346 consdata = SCIPconsGetData(cons);
9347 assert(consdata != NULL);
9348
9349 /* if a cutoff was already detected just return */
9350 if( *cutoff )
9351 return SCIP_OKAY;
9352
9353 capacity = consdata->capacity;
9354
9355 for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9356 {
9357 if( consdata->demands[j] > capacity )
9358 {
9359 SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9360
9361 /* remove variable form constraint */
9362 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9363 (*nchgcoefs)++;
9364 }
9365 }
9366
9367 SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9368
9369 return SCIP_OKAY;
9370}
9371
9372/** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9373static
9375 SCIP* scip, /**< SCIP data structure */
9376 SCIP_VAR* var, /**< integer variable to fix */
9377 SCIP_Bool uplock, /**< has thet start time variable a up lock */
9378 int* nfixedvars /**< pointer to store the number fixed variables */
9379 )
9380{
9381 SCIP_Bool infeasible;
9382 SCIP_Bool tightened;
9383 SCIP_Bool roundable;
9384
9385 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9386 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9387 */
9389 return SCIP_OKAY;
9390
9391 /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9392 * handler is the only one locking that variable up
9393 */
9394 assert(uplock == TRUE || uplock == FALSE);
9395 assert((int)TRUE == 1); /*lint !e506*/
9396 assert((int)FALSE == 0); /*lint !e506*/
9397
9398 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9399 return SCIP_OKAY;
9400
9401 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9402
9403 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9404 * (the transformed problem is always a minimization problem)
9405 */
9406 if( !roundable )
9407 return SCIP_OKAY;
9408
9409 SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9411
9412 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9413 assert(!infeasible);
9414
9415 if( tightened )
9416 {
9417 SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9418 (*nfixedvars)++;
9419 }
9420
9421 return SCIP_OKAY;
9422}
9423
9424/** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9425static
9427 SCIP* scip, /**< SCIP data structure */
9428 SCIP_VAR* var, /**< integer variable to fix */
9429 SCIP_Bool downlock, /**< has the variable a down lock */
9430 int* nfixedvars /**< pointer to store the number fixed variables */
9431 )
9432{
9433 SCIP_Bool infeasible;
9434 SCIP_Bool tightened;
9435 SCIP_Bool roundable;
9436
9437 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9438 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9439 */
9441 return SCIP_OKAY;
9442
9443 /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9444 * handler is the only one locking that variable down
9445 */
9446 assert(downlock == TRUE || downlock == FALSE);
9447 assert((int)TRUE == 1); /*lint !e506*/
9448 assert((int)FALSE == 0); /*lint !e506*/
9449
9450 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9451 return SCIP_OKAY;
9452
9453 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9454
9455 /* is it possible, to round variable down w.r.t. objective function? */
9456 if( !roundable )
9457 return SCIP_OKAY;
9458
9459 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9460 assert(!infeasible);
9461
9462 if( tightened )
9463 {
9464 SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9465 (*nfixedvars)++;
9466 }
9467
9468 return SCIP_OKAY;
9469}
9470
9471/** normalize cumulative condition */
9472static
9474 SCIP* scip, /**< SCIP data structure */
9475 int nvars, /**< number of start time variables (activities) */
9476 int* demands, /**< array of demands */
9477 int* capacity, /**< pointer to store the changed cumulative capacity */
9478 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9479 int* nchgsides /**< pointer to count number of side changes */
9480 )
9481{ /*lint --e{715}*/
9482 SCIP_Longint gcd;
9483 int mindemand1;
9484 int mindemand2;
9485 int v;
9486
9487 if( *capacity == 1 || nvars <= 1 )
9488 return;
9489
9490 assert(demands[nvars-1] <= *capacity);
9491 assert(demands[nvars-2] <= *capacity);
9492
9493 gcd = (SCIP_Longint)demands[nvars-1];
9494 mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9495 mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9496
9497 for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9498 {
9499 assert(mindemand1 <= mindemand2);
9500 assert(demands[v] <= *capacity);
9501
9502 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9503
9504 if( mindemand1 > demands[v] )
9505 {
9506 mindemand2 = mindemand1;
9507 mindemand1 = demands[v];
9508 }
9509 else if( mindemand2 > demands[v] )
9510 mindemand2 = demands[v];
9511 }
9512
9513 if( mindemand1 + mindemand2 > *capacity )
9514 {
9515 SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9516
9517 for( v = 0; v < nvars; ++v )
9518 demands[v] = 1;
9519
9520 (*capacity) = 1;
9521
9522 (*nchgcoefs) += nvars;
9523 (*nchgsides)++;
9524 }
9525 else if( gcd >= 2 )
9526 {
9527 SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9528
9529 for( v = 0; v < nvars; ++v )
9530 demands[v] /= (int) gcd;
9531
9532 (*capacity) /= (int) gcd;
9533
9534 (*nchgcoefs) += nvars;
9535 (*nchgsides)++;
9536 }
9537}
9538
9539/** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9540 * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9541 * capacity since in that case none of the jobs can run in parallel
9542 */
9543static
9545 SCIP* scip, /**< SCIP data structure */
9546 SCIP_CONS* cons, /**< cumulative constraint */
9547 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9548 int* nchgsides /**< pointer to count number of side changes */
9549 )
9550{
9551 SCIP_CONSDATA* consdata;
9552 int capacity;
9553
9554 assert(nchgcoefs != NULL);
9555 assert(nchgsides != NULL);
9556 assert(!SCIPconsIsModifiable(cons));
9557
9558 consdata = SCIPconsGetData(cons);
9559 assert(consdata != NULL);
9560
9561 if( consdata->normalized )
9562 return;
9563
9564 capacity = consdata->capacity;
9565
9566 /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9567
9568 normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9569
9570 consdata->normalized = TRUE;
9571
9572 if( capacity > consdata->capacity )
9573 consdata->varbounds = FALSE;
9574}
9575
9576/** computes for the given cumulative condition the effective horizon */
9577static
9579 SCIP* scip, /**< SCIP data structure */
9580 int nvars, /**< number of variables (jobs) */
9581 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9582 int* durations, /**< array containing corresponding durations */
9583 int* demands, /**< array containing corresponding demands */
9584 int capacity, /**< available cumulative capacity */
9585 int* hmin, /**< pointer to store the left bound of the effective horizon */
9586 int* hmax, /**< pointer to store the right bound of the effective horizon */
9587 int* split /**< point were the cumulative condition can be split */
9588 )
9589{
9590 SCIP_PROFILE* profile;
9591
9592 /* create empty resource profile with infinity resource capacity */
9593 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9594
9595 /* create worst case resource profile */
9596 SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9597
9598 /* print resource profile in if SCIP_DEBUG is defined */
9600
9601 /* computes the first time point where the resource capacity can be violated */
9602 (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9603
9604 /* computes the first time point where the resource capacity is satisfied for sure */
9605 (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9606
9607 (*split) = (*hmax);
9608
9609 if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9610 {
9611 int* timepoints;
9612 int* loads;
9613 int ntimepoints;
9614 int t;
9615
9616 /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9617 * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9618 * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9619 * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9620 * explain the certain "old" bound changes
9621 */
9622
9623 /* search for time points */
9624 ntimepoints = SCIPprofileGetNTimepoints(profile);
9625 timepoints = SCIPprofileGetTimepoints(profile);
9626 loads = SCIPprofileGetLoads(profile);
9627
9628 /* 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 */
9629 for( t = 0; t < ntimepoints; ++t )
9630 {
9631 /* ignore all time points before the effective horizon */
9632 if( timepoints[t] <= *hmin )
9633 continue;
9634
9635 /* ignore all time points after the effective horizon */
9636 if( timepoints[t] >= *hmax )
9637 break;
9638
9639 /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9640 * can split the cumulative constraint into two cumulative constraints
9641 */
9642 if( loads[t] <= capacity )
9643 {
9644 (*split) = timepoints[t];
9645 break;
9646 }
9647 }
9648 }
9649
9650 /* free worst case profile */
9651 SCIPprofileFree(&profile);
9652
9653 return SCIP_OKAY;
9654}
9655
9656/** creates and adds a cumulative constraint */
9657static
9659 SCIP* scip, /**< SCIP data structure */
9660 const char* name, /**< name of constraint */
9661 int nvars, /**< number of variables (jobs) */
9662 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9663 int* durations, /**< array containing corresponding durations */
9664 int* demands, /**< array containing corresponding demands */
9665 int capacity, /**< available cumulative capacity */
9666 int hmin, /**< left bound of time axis to be considered (including hmin) */
9667 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9668 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9669 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9670 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9671 * Usually set to TRUE. */
9672 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9673 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9674 SCIP_Bool check, /**< should the constraint be checked for feasibility?
9675 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9676 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9677 * Usually set to TRUE. */
9678 SCIP_Bool local, /**< is constraint only valid locally?
9679 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9680 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9681 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9682 * adds coefficients to this constraint. */
9683 SCIP_Bool dynamic, /**< is constraint subject to aging?
9684 * Usually set to FALSE. Set to TRUE for own cuts which
9685 * are seperated as constraints. */
9686 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9687 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9688 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9689 * if it may be moved to a more global node?
9690 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9691 )
9692{
9693 SCIP_CONS* cons;
9694
9695 /* creates cumulative constraint and adds it to problem */
9696 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9697 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9698
9699 /* adjust the effective time horizon of the new constraint */
9700 SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9701 SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9702
9703 /* add and release new cumulative constraint */
9704 SCIP_CALL( SCIPaddCons(scip, cons) );
9705 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9706
9707 return SCIP_OKAY;
9708}
9709
9710/** computes the effective horizon and checks if the constraint can be decompsed */
9711static
9713 SCIP* scip, /**< SCIP data structure */
9714 SCIP_CONS* cons, /**< cumulative constraint */
9715 int* ndelconss, /**< pointer to store the number of deleted constraints */
9716 int* naddconss, /**< pointer to store the number of added constraints */
9717 int* nchgsides /**< pointer to store the number of changed sides */
9718 )
9719{
9720 SCIP_CONSDATA* consdata;
9721 int hmin;
9722 int hmax;
9723 int split;
9724
9725 consdata = SCIPconsGetData(cons);
9726 assert(consdata != NULL);
9727
9728 if( consdata->nvars <= 1 )
9729 return SCIP_OKAY;
9730
9731 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9732 consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9733
9734 /* check if this time point improves the effective horizon */
9735 if( consdata->hmin < hmin )
9736 {
9737 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9738
9739 consdata->hmin = hmin;
9740 (*nchgsides)++;
9741 }
9742
9743 /* check if this time point improves the effective horizon */
9744 if( consdata->hmax > hmax )
9745 {
9746 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9747 consdata->hmax = hmax;
9748 (*nchgsides)++;
9749 }
9750
9751 /* check if the constraint is redundant */
9752 if( consdata->hmax <= consdata->hmin )
9753 {
9754 SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9755 SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9756
9757 SCIP_CALL( SCIPdelCons(scip, cons) );
9758 (*ndelconss)++;
9759 }
9760 else if( consdata->hmin < split && split < consdata->hmax )
9761 {
9762 char name[SCIP_MAXSTRLEN];
9763 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9764
9765 SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9766 SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9767
9768 assert(split < consdata->hmax);
9769
9770 /* creates cumulative constraint and adds it to problem */
9771 SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9772 consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9775
9776 /* adjust the effective time horizon of the constraint */
9777 consdata->hmax = split;
9778
9779 assert(consdata->hmin < consdata->hmax);
9780
9781 /* for the statistic we count the number of time we decompose a cumulative constraint */
9783 (*naddconss)++;
9784 }
9785
9786 return SCIP_OKAY;
9787}
9788
9789
9790/** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9791 *
9792 * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9793 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9794 *
9795 * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9796 * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9797 * down-lock of the corresponding start time variable can be removed.
9798 *
9799 * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9800 * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9801 * negative, than the job can be dual fixed to its earlier start time (est).
9802 *
9803 * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9804 * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9805 * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9806 *
9807 * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9808 * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9809 * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9810 * form variable domain is dual feasible.
9811 *
9812 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9813 * the cumulative condition; The deletion has to be done later.
9814 */
9815static
9817 SCIP* scip, /**< SCIP data structure */
9818 int nvars, /**< number of start time variables (activities) */
9819 SCIP_VAR** vars, /**< array of start time variables */
9820 int* durations, /**< array of durations */
9821 int hmin, /**< left bound of time axis to be considered (including hmin) */
9822 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9823 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9824 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9825 SCIP_CONS* cons, /**< underlying constraint, or NULL */
9826 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9827 int* nfixedvars, /**< pointer to store the number of fixed variables */
9828 int* nchgsides, /**< pointer to store the number of changed sides */
9829 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9830 )
9831{
9832 SCIP_Real* downimpllbs;
9833 SCIP_Real* downimplubs;
9834 SCIP_Real* downproplbs;
9835 SCIP_Real* downpropubs;
9836 SCIP_Real* upimpllbs;
9837 SCIP_Real* upimplubs;
9838 SCIP_Real* upproplbs;
9839 SCIP_Real* uppropubs;
9840
9841 int firstminect;
9842 int secondminect;
9843 int v;
9844
9845 /* get temporary memory for storing probing results needed for step (4) and (5) */
9846 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9847 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9848 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9849 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9850 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9851 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9852 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9853 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9854
9855 assert(scip != NULL);
9856 assert(nvars > 1);
9857 assert(cons != NULL);
9858
9859 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9860
9861 firstminect = INT_MAX;
9862 secondminect = INT_MAX;
9863
9864 /* compute the two smallest earlier completion times; which are needed for step (5) */
9865 for( v = 0; v < nvars; ++v )
9866 {
9867 int ect;
9868
9869 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9870
9871 if( ect < firstminect )
9872 {
9873 secondminect = firstminect;
9874 firstminect = ect;
9875 }
9876 else if( ect < secondminect )
9877 secondminect = ect;
9878 }
9879
9880 /* loop over all jobs and check if one of the 5 reductions can be applied */
9881 for( v = 0; v < nvars; ++v )
9882 {
9883 SCIP_VAR* var;
9884 int duration;
9885
9886 int alternativelb;
9887 int minect;
9888 int est;
9889 int ect;
9890 int lst;
9891 int lct;
9892
9893 var = vars[v];
9894 assert(var != NULL);
9895
9896 duration = durations[v];
9897 assert(duration > 0);
9898
9899 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9900 * time (lct)
9901 */
9903 ect = est + duration;
9905 lct = lst + duration;
9906
9907 /* compute the earliest completion time of all remaining jobs */
9908 if( ect == firstminect )
9909 minect = secondminect;
9910 else
9911 minect = firstminect;
9912
9913 /* compute potential alternative lower bound (step (4) and (5)) */
9914 alternativelb = MAX(hmin+1, minect);
9915 alternativelb = MIN(alternativelb, hmax);
9916
9917 if( lct <= hmin )
9918 {
9919 /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9920 * cumulative condition
9921 */
9922 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9923 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9924
9925 /* mark variable to be irrelevant */
9926 irrelevants[v] = TRUE;
9927
9928 /* for the statistic we count the number of jobs which are irrelevant */
9930 }
9931 else if( lst <= hmin && SCIPconsIsChecked(cons) )
9932 {
9933 /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9934 * so the down lock can be omitted
9935 */
9936
9937 assert(downlocks != NULL);
9938 assert(uplocks != NULL);
9939
9940 if( !uplocks[v] )
9941 {
9942 /* the variables has no up lock and we can also remove the down lock;
9943 * => lst <= hmin and ect >= hmax
9944 * => remove job and reduce capacity by the demand of that job
9945 *
9946 * We mark the job to be deletable. The removement together with the capacity reducion is done later
9947 */
9948
9949 SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
9950 SCIPvarGetName(var), ect - duration, lst, duration);
9951
9952 /* mark variable to be irrelevant */
9953 irrelevants[v] = TRUE;
9954
9955 /* for the statistic we count the number of jobs which always run during the effective horizon */
9957 }
9958
9959 if( downlocks[v] )
9960 {
9961 SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
9962 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9963
9964 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
9965 downlocks[v] = FALSE;
9966 (*nchgsides)++;
9967
9968 /* for the statistic we count the number of removed locks */
9970 }
9971 }
9972 else if( ect <= hmin )
9973 {
9974 /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
9975 * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
9976 * removed form the cumulative condition after it was fixed to its earliest start time
9977 */
9978
9979 /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
9980 * bound;
9981 */
9982 if( downlocks != NULL && SCIPconsIsChecked(cons) )
9983 {
9984 /* fix integer start time variable if possible to it lower bound */
9985 SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
9986 }
9987
9988 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
9989 {
9990 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
9991 SCIPvarGetName(var), ect - duration, lst, duration);
9992
9993 /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
9994 assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
9995
9996 /* mark variable to be irrelevant */
9997 irrelevants[v] = TRUE;
9998
9999 /* for the statistic we count the number of jobs which are dual fixed */
10001 }
10002 }
10003 else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10004 {
10005 assert(downlocks != NULL);
10006
10007 /* check step (4) and (5) */
10008
10009 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10010 * is in favor of rounding the variable down
10011 */
10012 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10013 {
10014 SCIP_Bool roundable;
10015
10016 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10017
10018 if( roundable )
10019 {
10020 if( alternativelb > lst )
10021 {
10022 SCIP_Bool infeasible;
10023 SCIP_Bool fixed;
10024
10025 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10026 assert(!infeasible);
10027 assert(fixed);
10028
10029 (*nfixedvars)++;
10030
10031 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10032 * constraints
10033 */
10035 }
10036 else
10037 {
10038 SCIP_Bool success;
10039
10040 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10041 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10042 * infeasible we can apply the dual reduction; otherwise we do nothing
10043 */
10044 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10045 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10046 nfixedvars, &success, cutoff) );
10047
10048 if( success )
10049 {
10051 }
10052 }
10053 }
10054 }
10055 }
10056
10057 SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10058 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10059 }
10060
10061 /* free temporary memory */
10062 SCIPfreeBufferArray(scip, &uppropubs);
10063 SCIPfreeBufferArray(scip, &upproplbs);
10064 SCIPfreeBufferArray(scip, &upimplubs);
10065 SCIPfreeBufferArray(scip, &upimpllbs);
10066 SCIPfreeBufferArray(scip, &downpropubs);
10067 SCIPfreeBufferArray(scip, &downproplbs);
10068 SCIPfreeBufferArray(scip, &downimplubs);
10069 SCIPfreeBufferArray(scip, &downimpllbs);
10070
10071 return SCIP_OKAY;
10072}
10073
10074/** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10075 *
10076 * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10077 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10078 *
10079 * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10080 * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10081 * up-lock of the corresponding start time variable can be removed.
10082 *
10083 * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10084 * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10085 * positive, than the job can be dual fixed to its latest start time (lst).
10086 *
10087 * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10088 * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10089 * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10090 * of the corresponding job).
10091
10092 * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10093 * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10094 * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10095 * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10096 *
10097 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10098 * the cumulative condition; The deletion has to be done later.
10099 */
10100static
10102 SCIP* scip, /**< SCIP data structure */
10103 int nvars, /**< number of start time variables (activities) */
10104 SCIP_VAR** vars, /**< array of start time variables */
10105 int* durations, /**< array of durations */
10106 int hmin, /**< left bound of time axis to be considered (including hmin) */
10107 int hmax, /**< right bound of time axis to be considered (not including hmax) */
10108 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10109 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10110 SCIP_CONS* cons, /**< underlying constraint, or NULL */
10111 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10112 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10113 int* nchgsides, /**< pointer to store the number of changed sides */
10114 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10115 )
10116{
10117 SCIP_Real* downimpllbs;
10118 SCIP_Real* downimplubs;
10119 SCIP_Real* downproplbs;
10120 SCIP_Real* downpropubs;
10121 SCIP_Real* upimpllbs;
10122 SCIP_Real* upimplubs;
10123 SCIP_Real* upproplbs;
10124 SCIP_Real* uppropubs;
10125
10126 int firstmaxlst;
10127 int secondmaxlst;
10128 int v;
10129
10130 /* get temporary memory for storing probing results needed for step (4) and (5) */
10131 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10132 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10133 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10134 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10135 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10136 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10137 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10138 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10139
10140 assert(scip != NULL);
10141 assert(nvars > 1);
10142 assert(cons != NULL);
10143
10144 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10145
10146 firstmaxlst = INT_MIN;
10147 secondmaxlst = INT_MIN;
10148
10149 /* compute the two largest latest start times; which are needed for step (5) */
10150 for( v = 0; v < nvars; ++v )
10151 {
10152 int lst;
10153
10155
10156 if( lst > firstmaxlst )
10157 {
10158 secondmaxlst = firstmaxlst;
10159 firstmaxlst = lst;
10160 }
10161 else if( lst > secondmaxlst )
10162 secondmaxlst = lst;
10163 }
10164
10165 /* loop over all jobs and check if one of the 5 reductions can be applied */
10166 for( v = 0; v < nvars; ++v )
10167 {
10168 SCIP_VAR* var;
10169 int duration;
10170
10171 int alternativeub;
10172 int maxlst;
10173 int est;
10174 int ect;
10175 int lst;
10176
10177 var = vars[v];
10178 assert(var != NULL);
10179
10180 duration = durations[v];
10181 assert(duration > 0);
10182
10183 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10184 * time (lct)
10185 */
10187 ect = est + duration;
10189
10190 /* compute the latest start time of all remaining jobs */
10191 if( lst == firstmaxlst )
10192 maxlst = secondmaxlst;
10193 else
10194 maxlst = firstmaxlst;
10195
10196 /* compute potential alternative upper bound (step (4) and (5)) */
10197 alternativeub = MIN(hmax - 1, maxlst) - duration;
10198 alternativeub = MAX(alternativeub, hmin);
10199
10200 if( est >= hmax )
10201 {
10202 /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10203 * cumulative condition
10204 */
10205 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10206 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10207
10208 /* mark variable to be irrelevant */
10209 irrelevants[v] = TRUE;
10210
10211 /* for the statistic we count the number of jobs which are irrelevant */
10213 }
10214 else if( ect >= hmax && SCIPconsIsChecked(cons) )
10215 {
10216 assert(downlocks != NULL);
10217 assert(uplocks != NULL);
10218
10219 /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10220 * so the up lock can be omitted
10221 */
10222
10223 if( !downlocks[v] )
10224 {
10225 /* the variables has no down lock and we can also remove the up lock;
10226 * => lst <= hmin and ect >= hmax
10227 * => remove job and reduce capacity by the demand of that job
10228 */
10229 SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10230 SCIPvarGetName(var), est, lst, duration);
10231
10232 /* mark variable to be irrelevant */
10233 irrelevants[v] = TRUE;
10234
10235 /* for the statistic we count the number of jobs which always run during the effective horizon */
10237 }
10238
10239 if( uplocks[v] )
10240 {
10241 SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10242 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10243
10244 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10245 uplocks[v] = FALSE;
10246 (*nchgsides)++;
10247
10248 /* for the statistic we count the number of removed locks */
10250 }
10251 }
10252 else if( lst >= hmax )
10253 {
10254 /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10255 * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10256 * removed form the cumulative condition after it was fixed to its latest start time
10257 */
10258
10259 /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10260 * bound
10261 */
10262 if( uplocks != NULL && SCIPconsIsChecked(cons) )
10263 {
10264 /* fix integer start time variable if possible to its upper bound */
10265 SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10266 }
10267
10268 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10269 {
10270 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10271 SCIPvarGetName(var), est, lst, duration);
10272
10273 /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10274 assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10275
10276 /* mark variable to be irrelevant */
10277 irrelevants[v] = TRUE;
10278
10279 /* for the statistic we count the number of jobs which are dual fixed */
10281 }
10282 }
10283 else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10284 {
10285 assert(uplocks != NULL);
10286
10287 /* check step (4) and (5) */
10288
10289 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10290 * is in favor of rounding the variable down
10291 */
10292 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10293 {
10294 SCIP_Bool roundable;
10295
10296 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10297
10298 if( roundable )
10299 {
10300 if( alternativeub < est )
10301 {
10302 SCIP_Bool infeasible;
10303 SCIP_Bool fixed;
10304
10305 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10306 assert(!infeasible);
10307 assert(fixed);
10308
10309 (*nfixedvars)++;
10310
10311 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10312 * constraints
10313 */
10315 }
10316 else
10317 {
10318 SCIP_Bool success;
10319
10320 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10321 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10322 * in infeasible we can apply the dual reduction; otherwise we do nothing
10323 */
10324 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10325 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10326 nfixedvars, &success, cutoff) );
10327
10328 if( success )
10329 {
10331 }
10332 }
10333 }
10334 }
10335 }
10336 }
10337
10338 /* free temporary memory */
10339 SCIPfreeBufferArray(scip, &uppropubs);
10340 SCIPfreeBufferArray(scip, &upproplbs);
10341 SCIPfreeBufferArray(scip, &upimplubs);
10342 SCIPfreeBufferArray(scip, &upimpllbs);
10343 SCIPfreeBufferArray(scip, &downpropubs);
10344 SCIPfreeBufferArray(scip, &downproplbs);
10345 SCIPfreeBufferArray(scip, &downimplubs);
10346 SCIPfreeBufferArray(scip, &downimpllbs);
10347
10348 return SCIP_OKAY;
10349}
10350
10351/** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10352static
10354 SCIP* scip, /**< SCIP data structure */
10355 SCIP_CONS* cons, /**< cumulative constraint */
10356 int* nfixedvars, /**< pointer to store the number of fixed variables */
10357 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10358 int* nchgsides, /**< pointer to store the number of changed sides */
10359 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10360 )
10361{
10362 SCIP_CONSDATA* consdata;
10363 SCIP_Bool* irrelevants;
10364 int nvars;
10365 int v;
10366
10367 assert(scip != NULL);
10368 assert(cons != NULL);
10369 assert(!(*cutoff));
10370
10371 consdata = SCIPconsGetData(cons);
10372 assert(consdata != NULL);
10373
10374 nvars = consdata->nvars;
10375
10376 if( nvars <= 1 )
10377 return SCIP_OKAY;
10378
10379 SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10380 BMSclearMemoryArray(irrelevants, nvars);
10381
10382 /* presolve constraint form the earlier start time point of view */
10383 SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10384 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10385 irrelevants, nfixedvars, nchgsides, cutoff) );
10386
10387 /* presolve constraint form the latest completion time point of view */
10388 SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10389 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10390 irrelevants, nfixedvars, nchgsides, cutoff) );
10391
10392 /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10393 * order to ensure a correct behaviour
10394 */
10395 for( v = nvars-1; v >= 0; --v )
10396 {
10397 if( irrelevants[v] )
10398 {
10399 SCIP_VAR* var;
10400 int ect;
10401 int lst;
10402
10403 var = consdata->vars[v];
10404 assert(var != NULL);
10405
10406 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10408
10409 /* check if the jobs runs completely during the effective horizon */
10410 if( lst <= consdata->hmin && ect >= consdata->hmax )
10411 {
10412 if( consdata->capacity < consdata->demands[v] )
10413 {
10414 *cutoff = TRUE;
10415 break;
10416 }
10417
10418 consdata->capacity -= consdata->demands[v];
10419 consdata->varbounds = FALSE;
10420 }
10421
10422 SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10423 (*nchgcoefs)++;
10424 }
10425 }
10426
10427 SCIPfreeBufferArray(scip, &irrelevants);
10428
10429 return SCIP_OKAY;
10430}
10431
10432/** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10433static
10435 SCIP* scip, /**< SCIP data structure */
10436 SCIP_CONSDATA* consdata, /**< constraint data */
10437 int* startindices, /**< permutation with rspect to the start times */
10438 int curtime, /**< current point in time */
10439 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10440 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10441 SCIP_Longint** demands, /**< pointer to array storing the demands */
10442 int* ndemands /**< pointer to store the number of different demands */
10443 )
10444{
10445 int startindex;
10446 int ncountedvars;
10447
10448 assert(demands != NULL);
10449 assert(ndemands != NULL);
10450
10451 ncountedvars = 0;
10452 startindex = nstarted - 1;
10453
10454 *ndemands = 0;
10455
10456 /* search for the (nstarted - nfinished) jobs which are active at curtime */
10457 while( nstarted - nfinished > ncountedvars )
10458 {
10459 SCIP_VAR* var;
10460 int endtime;
10461 int varidx;
10462
10463 /* collect job information */
10464 varidx = startindices[startindex];
10465 assert(varidx >= 0 && varidx < consdata->nvars);
10466
10467 var = consdata->vars[varidx];
10468 assert(var != NULL);
10469
10470 endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10471
10472 /* check the end time of this job is larger than the curtime; in this case the job is still running */
10473 if( endtime > curtime )
10474 {
10475 if( consdata->demands[varidx] < consdata->capacity )
10476 {
10477 (*demands)[*ndemands] = consdata->demands[varidx];
10478 (*ndemands)++;
10479 }
10480 ncountedvars++;
10481 }
10482
10483 startindex--;
10484 }
10485}
10486
10487/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10488 * constraint
10489 */
10490static
10492 SCIP* scip, /**< SCIP data structure */
10493 SCIP_CONS* cons, /**< constraint to be checked */
10494 int* startindices, /**< permutation with rspect to the start times */
10495 int curtime, /**< current point in time */
10496 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10497 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10498 int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10499 )
10500{
10501 SCIP_CONSDATA* consdata;
10502 SCIP_Longint* demands;
10503 SCIP_Real* profits;
10504 int* items;
10505 int ndemands;
10506 SCIP_Bool success;
10507 SCIP_Real solval;
10508 int j;
10509 assert(nstarted > nfinished);
10510
10511 consdata = SCIPconsGetData(cons);
10512 assert(consdata != NULL);
10513 assert(consdata->nvars > 0);
10514 assert(consdata->capacity > 0);
10515
10516 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10517 ndemands = 0;
10518
10519 /* get demand array to initialize knapsack problem */
10520 collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10521
10522 /* create array for profits */
10523 SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10524 SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10525 for( j = 0; j < ndemands; ++j )
10526 {
10527 profits[j] = (SCIP_Real) demands[j];
10528 items[j] = j;/* this is only a dummy value*/
10529 }
10530
10531 /* solve knapsack problem and get maximum capacity usage <= capacity */
10532 SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10533 items, NULL, NULL, NULL, NULL, &solval, &success) );
10534
10535 assert(SCIPisFeasIntegral(scip, solval));
10536
10537 /* store result */
10538 *bestcapacity = SCIPconvertRealToInt(scip, solval);
10539
10540 SCIPfreeBufferArray(scip, &items);
10541 SCIPfreeBufferArray(scip, &profits);
10542 SCIPfreeBufferArray(scip, &demands);
10543
10544 return SCIP_OKAY;
10545}
10546
10547/** try to tighten the capacity
10548 * -- using DP for knapsack, we find the maximum possible capacity usage
10549 * -- neglects hmin and hmax, such that it is also able to check solutions globally
10550 */
10551static
10553 SCIP* scip, /**< SCIP data structure */
10554 SCIP_CONS* cons, /**< cumulative constraint */
10555 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10556 int* nchgsides /**< pointer to store the number of changed sides */
10557 )
10558{
10559 SCIP_CONSDATA* consdata;
10560 int* starttimes; /* stores when each job is starting */
10561 int* endtimes; /* stores when each job ends */
10562 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10563 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10564
10565 int nvars; /* number of activities for this constraint */
10566 int freecapacity; /* remaining capacity */
10567 int curtime; /* point in time which we are just checking */
10568 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10569
10570 int bestcapacity;
10571
10572 int j;
10573
10574 assert(scip != NULL);
10575 assert(cons != NULL);
10576 assert(nchgsides != NULL);
10577
10578 consdata = SCIPconsGetData(cons);
10579 assert(consdata != NULL);
10580
10581 nvars = consdata->nvars;
10582
10583 /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10584 if( nvars <= 1 || consdata->capacity <= 1 )
10585 return SCIP_OKAY;
10586
10587 assert(consdata->vars != NULL);
10588
10589 SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10590 SCIPconsGetName(cons), consdata->capacity);
10591
10592 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10593 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10594 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10595 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10596
10597 /* create event point arrays */
10598 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10599 starttimes, endtimes, startindices, endindices, FALSE);
10600
10601 bestcapacity = 1;
10602 endindex = 0;
10603 freecapacity = consdata->capacity;
10604
10605 /* check each startpoint of a job whether the capacity is kept or not */
10606 for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10607 {
10608 curtime = starttimes[j];
10609 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10610
10611 /* remove the capacity requirments for all job which start at the curtime */
10612 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10613
10614 /* add the capacity requirments for all job which end at the curtime */
10615 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10616
10617 assert(freecapacity <= consdata->capacity);
10618 assert(endindex <= nvars);
10619
10620 /* endindex - points to the next job which will finish */
10621 /* j - points to the last job that has been released */
10622
10623 /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10624 if( freecapacity < 0 )
10625 {
10626 int newcapacity;
10627
10628 newcapacity = 1;
10629
10630 /* get best possible upper bound on capacity usage */
10631 SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10632
10633 /* update bestcapacity */
10634 bestcapacity = MAX(bestcapacity, newcapacity);
10635 SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10636 }
10637
10638 /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10639 if( freecapacity > 0 && freecapacity != consdata->capacity )
10640 {
10641 bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10642 SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10643 }
10644
10645 /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10646 if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10647 {
10648 /* if demands[startindices[j]] == cap then exactly that job is running */
10649 SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10650 bestcapacity = consdata->capacity;
10651 break;
10652 }
10653 } /*lint --e{850}*/
10654
10655 /* free all buffer arrays */
10656 SCIPfreeBufferArray(scip, &endindices);
10657 SCIPfreeBufferArray(scip, &startindices);
10658 SCIPfreeBufferArray(scip, &endtimes);
10659 SCIPfreeBufferArray(scip, &starttimes);
10660
10661 /* check whether capacity can be tightened and whether demands need to be adjusted */
10662 if( bestcapacity < consdata->capacity )
10663 {
10664 SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10665
10666 SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10667 SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10668
10669 for( j = 0; j < nvars; ++j )
10670 {
10671 if( consdata->demands[j] == consdata->capacity )
10672 {
10673 consdata->demands[j] = bestcapacity;
10674 (*nchgcoefs)++;
10675 }
10676 }
10677
10678 consdata->capacity = bestcapacity;
10679 (*nchgsides)++;
10680
10681 SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10682
10683 consdata->varbounds = FALSE;
10684 }
10685
10686 return SCIP_OKAY;
10687}
10688
10689/** tries to change coefficients:
10690 * demand_j < cap && all other parallel jobs in conflict
10691 * ==> set demand_j := cap
10692 */
10693static
10695 SCIP* scip, /**< SCIP data structure */
10696 SCIP_CONS* cons, /**< cumulative constraint */
10697 int* nchgcoefs /**< pointer to count total number of changed coefficients */
10698 )
10699{
10700 SCIP_CONSDATA* consdata;
10701 int nvars;
10702 int j;
10703 int oldnchgcoefs;
10704 int mindemand;
10705
10706 assert(scip != NULL);
10707 assert(cons != NULL);
10708 assert(nchgcoefs != NULL);
10709
10710 /* get constraint data for some parameter testings only! */
10711 consdata = SCIPconsGetData(cons);
10712 assert(consdata != NULL);
10713
10714 nvars = consdata->nvars;
10715 oldnchgcoefs = *nchgcoefs;
10716
10717 if( nvars <= 0 )
10718 return SCIP_OKAY;
10719
10720 /* PRE1:
10721 * check all jobs j whether: r_j + r_min > capacity holds
10722 * if so: adjust r_j to capacity
10723 */
10724 mindemand = consdata->demands[0];
10725 for( j = 0; j < nvars; ++j )
10726 {
10727 mindemand = MIN(mindemand, consdata->demands[j]);
10728 }
10729
10730 /*check each job */
10731 for( j = 0; j < nvars; ++j )
10732 {
10733 if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10734 {
10735 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10736 consdata->demands[j], consdata->capacity);
10737 consdata->demands[j] = consdata->capacity;
10738 (*nchgcoefs)++;
10739 }
10740 }
10741
10742 /* PRE2:
10743 * check for each job (with d_j < cap)
10744 * whether it is disjunctive to all others over the time horizon
10745 */
10746 for( j = 0; j < nvars; ++j )
10747 {
10748 SCIP_Bool chgcoef;
10749 int est_j;
10750 int lct_j;
10751 int i;
10752
10753 assert(consdata->demands[j] <= consdata->capacity);
10754
10755 if( consdata->demands[j] == consdata->capacity )
10756 continue;
10757
10758 chgcoef = TRUE;
10759
10760 est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10761 lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10762
10763 for( i = 0; i < nvars; ++i )
10764 {
10765 int est_i;
10766 int lct_i;
10767
10768 if( i == j )
10769 continue;
10770
10771 est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10772 lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10773
10774 if( est_i >= lct_j || est_j >= lct_i )
10775 continue;
10776
10777 if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10778 {
10779 chgcoef = FALSE;
10780 break;
10781 }
10782 }
10783
10784 if( chgcoef )
10785 {
10786 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10787 consdata->demands[j], consdata->capacity);
10788 consdata->demands[j] = consdata->capacity;
10789 (*nchgcoefs)++;
10790 }
10791 }
10792
10793 if( (*nchgcoefs) > oldnchgcoefs )
10794 {
10795 SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10796 (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10797 }
10798
10799 return SCIP_OKAY;
10800}
10801
10802#ifdef SCIP_DISABLED_CODE
10803/* The following should work, but does not seem to be tested well. */
10804
10805/** try to reformulate constraint by replacing certain jobs */
10806static
10807SCIP_RETCODE reformulateCons(
10808 SCIP* scip, /**< SCIP data structure */
10809 SCIP_CONS* cons, /**< cumulative constraint */
10810 int* naggrvars /**< pointer to store the number of aggregated variables */
10811 )
10812{
10813 SCIP_CONSDATA* consdata;
10814 int hmin;
10815 int hmax;
10816 int nvars;
10817 int v;
10818
10819 consdata = SCIPconsGetData(cons);
10820 assert(cons != NULL);
10821
10822 nvars = consdata->nvars;
10823 assert(nvars > 1);
10824
10825 hmin = consdata->hmin;
10826 hmax = consdata->hmax;
10827 assert(hmin < hmax);
10828
10829 for( v = 0; v < nvars; ++v )
10830 {
10831 SCIP_VAR* var;
10832 int duration;
10833 int est;
10834 int ect;
10835 int lst;
10836 int lct;
10837
10838 var = consdata->vars[v];
10839 assert(var != NULL);
10840
10841 duration = consdata->durations[v];
10842
10844 ect = est + duration;
10846 lct = lst + duration;
10847
10848 /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10849 assert(lst > hmin || ect < hmax);
10850
10851 if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10852 {
10853 SCIP_VAR* aggrvar;
10854 char name[SCIP_MAXSTRLEN];
10855 SCIP_Bool infeasible;
10856 SCIP_Bool redundant;
10857 SCIP_Bool aggregated;
10858 int shift;
10859
10860 shift = est - (hmin - lct + MIN(hmin, ect));
10861 assert(shift > 0);
10862 lst = hmin;
10863 duration = hmin - lct;
10864
10865 SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10866 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10867
10868 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10869 SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10871 SCIP_CALL( SCIPaddVar(scip, var) );
10872 SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10873
10874 assert(!infeasible);
10875 assert(!redundant);
10876 assert(aggregated);
10877
10878 /* replace variable */
10879 consdata->durations[v] = duration;
10880 consdata->vars[v] = aggrvar;
10881
10882 /* remove and add locks */
10883 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10884 SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10885
10886 SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10887
10888 (*naggrvars)++;
10889 }
10890 }
10891
10892 return SCIP_OKAY;
10893}
10894#endif
10895
10896/** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10897static
10899 SCIP* scip, /**< SCIP data structure */
10900 SCIP_CONS* cons, /**< cumulative constraint */
10901 int* naddconss /**< pointer to store the number of added constraints */
10902 )
10903{
10904 SCIP_CONSDATA* consdata;
10905 SCIP_VAR** vars;
10906 int* durations;
10907 int* demands;
10908 int capacity;
10909 int halfcapacity;
10910 int mindemand;
10911 int nvars;
10912 int v;
10913
10914 consdata = SCIPconsGetData(cons);
10915 assert(consdata != NULL);
10916
10917 capacity = consdata->capacity;
10918
10919 if( capacity == 1 )
10920 return SCIP_OKAY;
10921
10922 SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10923 SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10924 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10925
10926 halfcapacity = capacity / 2;
10927 mindemand = consdata->capacity;
10928 nvars = 0;
10929
10930 /* collect all jobs with demand larger than half of the capacity */
10931 for( v = 0; v < consdata->nvars; ++v )
10932 {
10933 if( consdata->demands[v] > halfcapacity )
10934 {
10935 vars[nvars] = consdata->vars[v];
10936 demands[nvars] = 1;
10937 durations[nvars] = consdata->durations[v];
10938 nvars++;
10939
10940 mindemand = MIN(mindemand, consdata->demands[v]);
10941 }
10942 }
10943
10944 if( nvars > 0 )
10945 {
10946 /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
10947 * job is still to large to be scheduled in parallel
10948 */
10949 for( v = 0; v < consdata->nvars; ++v )
10950 {
10951 if( consdata->demands[v] > halfcapacity )
10952 continue;
10953
10954 if( mindemand + consdata->demands[v] > capacity )
10955 {
10956 demands[nvars] = 1;
10957 durations[nvars] = consdata->durations[v];
10958 vars[nvars] = consdata->vars[v];
10959 nvars++;
10960
10961 /* @todo create one cumulative constraint and look for another small demand */
10962 break;
10963 }
10964 }
10965
10966 /* creates cumulative constraint and adds it to problem */
10967 SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
10969 (*naddconss)++;
10970 }
10971
10972 SCIPfreeBufferArray(scip, &demands);
10973 SCIPfreeBufferArray(scip, &durations);
10974 SCIPfreeBufferArray(scip, &vars);
10975
10976 return SCIP_OKAY;
10977}
10978
10979/** presolve given constraint */
10980static
10982 SCIP* scip, /**< SCIP data structure */
10983 SCIP_CONS* cons, /**< cumulative constraint */
10984 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
10985 SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
10986 int* nfixedvars, /**< pointer to store the number of fixed variables */
10987 int* nchgbds, /**< pointer to store the number of changed bounds */
10988 int* ndelconss, /**< pointer to store the number of deleted constraints */
10989 int* naddconss, /**< pointer to store the number of added constraints */
10990 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10991 int* nchgsides, /**< pointer to store the number of changed sides */
10992 SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
10993 SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
10994 )
10995{
10996 assert(!SCIPconsIsDeleted(cons));
10997
10998 /* only perform dual reductions on model constraints */
10999 if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11000 {
11001 /* computes the effective horizon and checks if the constraint can be decomposed */
11002 SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11003
11004 if( SCIPconsIsDeleted(cons) )
11005 return SCIP_OKAY;
11006
11007 /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11008 * fixings (dual reductions)
11009 */
11010 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11011 {
11012 SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11013
11014 if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11015 return SCIP_OKAY;
11016 }
11017
11018 SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11019
11020 if( *cutoff || SCIPconsIsDeleted(cons) )
11021 return SCIP_OKAY;
11022 }
11023
11024 /* remove jobs which have a demand larger than the capacity */
11025 SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11026 assert((*cutoff) || checkDemands(scip, cons));
11027
11028 if( *cutoff )
11029 return SCIP_OKAY;
11030
11031 if( conshdlrdata->normalize )
11032 {
11033 /* divide demands by their greatest common divisor */
11034 normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11035 }
11036
11037 /* delete constraint with one job */
11038 SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11039
11040 if( *cutoff || SCIPconsIsDeleted(cons) )
11041 return SCIP_OKAY;
11042
11043 if( conshdlrdata->coeftightening )
11044 {
11045 /* try to tighten the capacity */
11046 SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11047
11048 /* try to tighten the coefficients */
11049 SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11050 }
11051
11052 assert(checkDemands(scip, cons) || *cutoff);
11053
11054#ifdef SCIP_DISABLED_CODE
11055 /* The following should work, but does not seem to be tested well. */
11056 SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11057#endif
11058
11059 return SCIP_OKAY;
11060}
11061
11062/**@name TClique Graph callbacks
11063 *
11064 * @{
11065 */
11066
11067/** tclique graph data */
11068struct TCLIQUE_Graph
11069{
11070 SCIP_VAR** vars; /**< start time variables each of them is a node */
11071 SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11072 SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11073 SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11074 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11075 int* ninarcs; /**< number if in arcs for the precedence graph */
11076 int* noutarcs; /**< number if out arcs for the precedence graph */
11077 int* durations; /**< for each node the duration of the corresponding job */
11078 int nnodes; /**< number of nodes */
11079 int size; /**< size of the array */
11080};
11081
11082/** gets number of nodes in the graph */
11083static
11084TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11085{
11086 assert(tcliquegraph != NULL);
11087
11088 return tcliquegraph->nnodes;
11089}
11090
11091/** gets weight of nodes in the graph */
11092static
11093TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11094{
11095 assert(tcliquegraph != NULL);
11096
11097 return tcliquegraph->weights;
11098}
11099
11100/** returns, whether the edge (node1, node2) is in the graph */
11101static
11102TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11103{
11104 assert(tcliquegraph != NULL);
11105 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11106 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11107
11108 /* check if an arc exits in the precedence graph */
11109 if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11110 return TRUE;
11111
11112 /* check if an edge exits in the non-overlapping graph */
11113 if( tcliquegraph->demandmatrix[node1][node2] )
11114 return TRUE;
11115
11116 return FALSE;
11117}
11118
11119/** selects all nodes from a given set of nodes which are adjacent to a given node
11120 * and returns the number of selected nodes
11121 */
11122static
11123TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11124{
11125 int nadjnodes;
11126 int i;
11127
11128 assert(tcliquegraph != NULL);
11129 assert(0 <= node && node < tcliquegraph->nnodes);
11130 assert(nnodes == 0 || nodes != NULL);
11131 assert(adjnodes != NULL);
11132
11133 nadjnodes = 0;
11134
11135 for( i = 0; i < nnodes; i++ )
11136 {
11137 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11138 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11139 assert(i == 0 || nodes[i-1] < nodes[i]);
11140
11141 /* check if an edge exists */
11142 if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11143 {
11144 /* current node is adjacent to given node */
11145 adjnodes[nadjnodes] = nodes[i];
11146 nadjnodes++;
11147 }
11148 }
11149
11150 return nadjnodes;
11151}
11152
11153/** generates cuts using a clique found by algorithm for maximum weight clique
11154 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11155 */
11156static
11157TCLIQUE_NEWSOL(tcliqueNewsolClique)
11158{ /*lint --e{715}*/
11159 SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11160}
11161
11162
11163/** @} */
11164
11165/** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11166 * job corresponding to variable bound variable (vlbvar)
11167 *
11168 * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11169 */
11170static
11172 SCIP* scip, /**< SCIP data structure */
11173 SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11174 SCIP_Real vlbcoef, /**< variable bound coefficient */
11175 SCIP_Real vlbconst, /**< variable bound constant */
11176 int duration /**< duration of the variable bound variable */
11177 )
11178{
11179 if( SCIPisEQ(scip, vlbcoef, 1.0) )
11180 {
11181 if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11182 {
11183 /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11184 return TRUE;
11185 }
11186 }
11187 else
11188 {
11190
11191 bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11192
11193 if( SCIPisLT(scip, vlbcoef, 1.0) )
11194 {
11195 SCIP_Real ub;
11196
11197 ub = SCIPvarGetUbLocal(vlbvar);
11198
11199 /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11200 if( SCIPisLE(scip, ub, bound) )
11201 return TRUE;
11202 }
11203 else
11204 {
11205 SCIP_Real lb;
11206
11207 assert(SCIPisGT(scip, vlbcoef, 1.0));
11208
11209 lb = SCIPvarGetLbLocal(vlbvar);
11210
11211 /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11212 if( SCIPisGE(scip, lb, bound) )
11213 return TRUE;
11214 }
11215 }
11216
11217 return FALSE;
11218}
11219
11220/** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11221 * job corresponding to variable which is bounded (var)
11222 *
11223 * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11224 */
11225static
11227 SCIP* scip, /**< SCIP data structure */
11228 SCIP_VAR* var, /**< variable which is bound from above */
11229 SCIP_Real vubcoef, /**< variable bound coefficient */
11230 SCIP_Real vubconst, /**< variable bound constant */
11231 int duration /**< duration of the variable which is bounded from above */
11232 )
11233{
11234 SCIP_Real vlbcoef;
11235 SCIP_Real vlbconst;
11236
11237 /* convert the variable upper bound into an variable lower bound */
11238 vlbcoef = 1.0 / vubcoef;
11239 vlbconst = -vubconst / vubcoef;
11240
11241 return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11242}
11243
11244/** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11245 * others an index larger than the number if active variables
11246 */
11247static
11249 SCIP* scip, /**< SCIP data structure */
11250 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11251 SCIP_VAR* var, /**< variable for which we want the index */
11252 int* idx /**< pointer to store the index */
11253 )
11254{
11255 (*idx) = SCIPvarGetProbindex(var);
11256
11257 if( (*idx) == -1 )
11258 {
11259 if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11260 {
11261 (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11262 }
11263 else
11264 {
11265 int pos;
11266 int v;
11267
11268 /**@todo we might want to add the aggregation path to graph */
11269
11270 /* check if we have to realloc memory */
11271 if( tcliquegraph->size == tcliquegraph->nnodes )
11272 {
11273 int size;
11274
11275 size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11276 tcliquegraph->size = size;
11277
11278 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11279 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11280 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11281 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11282 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11283
11284 for( v = 0; v < tcliquegraph->nnodes; ++v )
11285 {
11286 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11287 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11288 }
11289 }
11290 assert(tcliquegraph->nnodes < tcliquegraph->size);
11291
11292 pos = tcliquegraph->nnodes;
11293 assert(pos >= 0);
11294
11295 tcliquegraph->durations[pos] = 0;
11296 tcliquegraph->weights[pos] = 0;
11297 tcliquegraph->vars[pos] = var;
11298
11299 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11300 BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11301
11302 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11303 BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11304
11305 SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11306
11307 tcliquegraph->nnodes++;
11308
11309 for( v = 0; v < tcliquegraph->nnodes; ++v )
11310 {
11311 tcliquegraph->precedencematrix[v][pos] = 0;
11312 tcliquegraph->demandmatrix[v][pos] = 0;
11313 }
11314
11315 (*idx) = tcliquegraph->nnodes;
11316 }
11317 }
11318 else
11319 {
11320 assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11321 }
11322
11323 assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11324
11325 return SCIP_OKAY;
11326}
11327
11328/** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11329 *
11330 * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11331 * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11332 *
11333 * (i) b = 1 and c >= d
11334 * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11335 * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11336 *
11337 */
11338static
11340 SCIP* scip, /**< SCIP data structure */
11341 TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11342 )
11343{
11344 SCIP_VAR** vars;
11345 int nvars;
11346 int v;
11347
11348 vars = SCIPgetVars(scip);
11349 nvars = SCIPgetNVars(scip);
11350
11351 /* try to project each arc of the variable bound graph to precedence condition */
11352 for( v = 0; v < nvars; ++v )
11353 {
11354 SCIP_VAR** vbdvars;
11355 SCIP_VAR* var;
11356 SCIP_Real* vbdcoefs;
11357 SCIP_Real* vbdconsts;
11358 int nvbdvars;
11359 int idx1;
11360 int b;
11361
11362 var = vars[v];
11363 assert(var != NULL);
11364
11365 SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11366 assert(idx1 >= 0);
11367
11368 if( tcliquegraph->durations[idx1] == 0 )
11369 continue;
11370
11371 vbdvars = SCIPvarGetVlbVars(var);
11372 vbdcoefs = SCIPvarGetVlbCoefs(var);
11373 vbdconsts = SCIPvarGetVlbConstants(var);
11374 nvbdvars = SCIPvarGetNVlbs(var);
11375
11376 for( b = 0; b < nvbdvars; ++b )
11377 {
11378 int idx2;
11379
11380 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11381 assert(idx2 >= 0);
11382
11383 if( tcliquegraph->durations[idx2] == 0 )
11384 continue;
11385
11386 if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11387 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11388 }
11389
11390 vbdvars = SCIPvarGetVubVars(var);
11391 vbdcoefs = SCIPvarGetVubCoefs(var);
11392 vbdconsts = SCIPvarGetVubConstants(var);
11393 nvbdvars = SCIPvarGetNVubs(var);
11394
11395 for( b = 0; b < nvbdvars; ++b )
11396 {
11397 int idx2;
11398
11399 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11400 assert(idx2 >= 0);
11401
11402 if( tcliquegraph->durations[idx2] == 0 )
11403 continue;
11404
11405 if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11406 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11407 }
11408
11409 for( b = v+1; b < nvars; ++b )
11410 {
11411 int idx2;
11412
11413 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11414 assert(idx2 >= 0);
11415
11416 if( tcliquegraph->durations[idx2] == 0 )
11417 continue;
11418
11419 /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11420 if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11421 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11422
11423 /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11424 if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11425 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11426 }
11427 }
11428
11429 return SCIP_OKAY;
11430}
11431
11432/** compute the transitive closer of the given graph and the number of in and out arcs */
11433static
11435 SCIP_Bool** adjmatrix, /**< adjacent matrix */
11436 int* ninarcs, /**< array to store the number of in arcs */
11437 int* noutarcs, /**< array to store the number of out arcs */
11438 int nnodes /**< number if nodes */
11439 )
11440{
11441 int i;
11442 int j;
11443 int k;
11444
11445 for( i = 0; i < nnodes; ++i )
11446 {
11447 for( j = 0; j < nnodes; ++j )
11448 {
11449 if( adjmatrix[i][j] )
11450 {
11451 ninarcs[j]++;
11452 noutarcs[i]++;
11453
11454 for( k = 0; k < nnodes; ++k )
11455 {
11456 if( adjmatrix[j][k] )
11457 adjmatrix[i][k] = TRUE;
11458 }
11459 }
11460 }
11461 }
11462}
11463
11464/** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11465static
11467 SCIP* scip, /**< SCIP data structure */
11468 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11469 SCIP_CONS** conss, /**< array of cumulative constraints */
11470 int nconss /**< number of cumulative constraints */
11471 )
11472{
11473 int c;
11474
11475 /* use the cumulative constraints to initialize the none overlapping graph */
11476 for( c = 0; c < nconss; ++c )
11477 {
11478 SCIP_CONSDATA* consdata;
11479 SCIP_VAR** vars;
11480 int* demands;
11481 int capacity;
11482 int nvars;
11483 int i;
11484
11485 consdata = SCIPconsGetData(conss[c]);
11486 assert(consdata != NULL);
11487
11488 vars = consdata->vars;
11489 demands = consdata->demands;
11490
11491 nvars = consdata->nvars;
11492 capacity = consdata->capacity;
11493
11494 SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11495
11496 /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11497 for( i = 0; i < nvars; ++i )
11498 {
11499 int idx1;
11500 int j;
11501
11502 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11503 assert(idx1 >= 0);
11504
11505 if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11506 continue;
11507
11508 for( j = i+1; j < nvars; ++j )
11509 {
11510 assert(consdata->durations[j] > 0);
11511
11512 if( demands[i] + demands[j] > capacity )
11513 {
11514 int idx2;
11515 int est1;
11516 int est2;
11517 int lct1;
11518 int lct2;
11519
11520 /* check if the effective horizon is large enough */
11523
11524 /* at least one of the jobs needs to start at hmin or later */
11525 if( est1 < consdata->hmin && est2 < consdata->hmin )
11526 continue;
11527
11528 lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11529 lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11530
11531 /* at least one of the jobs needs to finish not later then hmin */
11532 if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11533 continue;
11534
11535 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11536 assert(idx2 >= 0);
11537 assert(idx1 != idx2);
11538
11539 if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11540 continue;
11541
11542 SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11543
11544 assert(tcliquegraph->durations[idx1] > 0);
11545 assert(tcliquegraph->durations[idx2] > 0);
11546
11547 tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11548 tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11549 }
11550 }
11551 }
11552 }
11553
11554 return SCIP_OKAY;
11555}
11556
11557/** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11558 * of jobs cannot run in parallel
11559 */
11560static
11562 SCIP* scip, /**< SCIP data structure */
11563 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11564 SCIP_CONS** conss, /**< array of cumulative constraints */
11565 int nconss /**< number of cumulative constraints */
11566 )
11567{
11568 assert(scip != NULL);
11569 assert(tcliquegraph != NULL);
11570
11571 /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11572 SCIP_CALL( projectVbd(scip, tcliquegraph) );
11573
11574 /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11575 transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11576
11577 /* constraints non-overlapping graph */
11578 SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11579
11580 return SCIP_OKAY;
11581}
11582
11583/** create cumulative constraint from conflict set */
11584static
11586 SCIP* scip, /**< SCIP data structure */
11587 const char* name, /**< constraint name */
11588 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11589 int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11590 int ncliquenodes /**< number of nodes in the clique */
11591 )
11592{
11593 SCIP_CONS* cons;
11594 SCIP_VAR** vars;
11595 int* durations;
11596 int* demands;
11597 int v;
11598
11599 SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11600 SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11601 SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11602
11603 SCIPsortInt(cliquenodes, ncliquenodes);
11604
11605 /* collect variables, durations, and demands */
11606 for( v = 0; v < ncliquenodes; ++v )
11607 {
11608 durations[v] = tcliquegraph->durations[cliquenodes[v]];
11609 assert(durations[v] > 0);
11610 demands[v] = 1;
11611 vars[v] = tcliquegraph->vars[cliquenodes[v]];
11612 }
11613
11614 /* create (unary) cumulative constraint */
11615 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11617
11618 SCIP_CALL( SCIPaddCons(scip, cons) );
11619 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11620
11621 /* free buffers */
11622 SCIPfreeBufferArray(scip, &demands);
11623 SCIPfreeBufferArray(scip, &durations);
11624 SCIPfreeBufferArray(scip, &vars);
11625
11626 return SCIP_OKAY;
11627}
11628
11629/** search for cumulative constrainst */
11630static
11632 SCIP* scip, /**< SCIP data structure */
11633 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11634 int* naddconss /**< pointer to store the number of added constraints */
11635 )
11636{
11637 TCLIQUE_STATUS tcliquestatus;
11638 SCIP_Bool* precedencerow;
11639 SCIP_Bool* precedencecol;
11640 SCIP_Bool* demandrow;
11641 SCIP_Bool* demandcol;
11642 SCIP_HASHTABLE* covered;
11643 int* cliquenodes;
11644 int ncliquenodes;
11645 int cliqueweight;
11646 int ntreenodes;
11647 int nnodes;
11648 int nconss;
11649 int v;
11650
11651 nnodes = tcliquegraph->nnodes;
11652 nconss = 0;
11653
11654 /* initialize the weight of each job with its duration */
11655 for( v = 0; v < nnodes; ++v )
11656 {
11657 tcliquegraph->weights[v] = tcliquegraph->durations[v];
11658 }
11659
11660 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11661 SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11662 SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11663 SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11664 SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11665
11666 /* create a hash table to store all start time variables which are already covered by at least one clique */
11668 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11669
11670 /* for each variables/job we are ... */
11671 for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11672 {
11673 char name[SCIP_MAXSTRLEN];
11674 int c;
11675
11676 /* jobs with zero durations are skipped */
11677 if( tcliquegraph->durations[v] == 0 )
11678 continue;
11679
11680 /* check if the start time variable is already covered by at least one clique */
11681 if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11682 continue;
11683
11684 SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11685
11686 /* temporarily remove the connection via the precedence graph */
11687 for( c = 0; c < nnodes; ++c )
11688 {
11689 precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11690 precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11691
11692 demandrow[c] = tcliquegraph->demandmatrix[v][c];
11693 demandcol[c] = tcliquegraph->demandmatrix[c][v];
11694
11695 tcliquegraph->precedencematrix[c][v] = FALSE;
11696 tcliquegraph->precedencematrix[v][c] = FALSE;
11697 }
11698
11699 /* find (heuristically) maximum cliques which includes node v */
11700 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11701 tcliquegraph, tcliqueNewsolClique, NULL,
11702 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11703 10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11704
11705 SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11706
11707 if( ncliquenodes == 1 )
11708 continue;
11709
11710 /* construct constraint name */
11711 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11712
11713 SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11714 nconss++;
11715
11716 /* all start time variable to covered hash table */
11717 for( c = 0; c < ncliquenodes; ++c )
11718 {
11719 SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11720 }
11721
11722 /* copy the precedence relations back */
11723 for( c = 0; c < nnodes; ++c )
11724 {
11725 tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11726 tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11727
11728 tcliquegraph->demandmatrix[v][c] = demandrow[c];
11729 tcliquegraph->demandmatrix[c][v] = demandcol[c];
11730 }
11731 }
11732
11733 SCIPhashtableFree(&covered);
11734
11735 SCIPfreeBufferArray(scip, &demandcol);
11736 SCIPfreeBufferArray(scip, &demandrow);
11737 SCIPfreeBufferArray(scip, &precedencecol);
11738 SCIPfreeBufferArray(scip, &precedencerow);
11739 SCIPfreeBufferArray(scip, &cliquenodes);
11740
11741 (*naddconss) += nconss;
11742
11743 /* for the statistic we count the number added disjunctive constraints */
11744 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11745
11746 return SCIP_OKAY;
11747}
11748
11749/** create precedence constraint (as variable bound constraint */
11750static
11752 SCIP* scip, /**< SCIP data structure */
11753 const char* name, /**< constraint name */
11754 SCIP_VAR* var, /**< variable x that has variable bound */
11755 SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11756 int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11757 )
11758{
11759 SCIP_CONS* cons;
11760
11761 /* create variable bound constraint */
11762 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11764
11766
11767 /* add constraint to problem and release it */
11768 SCIP_CALL( SCIPaddCons(scip, cons) );
11769 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11770
11771 return SCIP_OKAY;
11772}
11773
11774/** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11775static
11777 SCIP* scip, /**< SCIP data structure */
11778 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11779 int source, /**< index of the source node */
11780 int sink, /**< index of the sink node */
11781 int* naddconss /**< pointer to store the number of added constraints */
11782 )
11783{
11784 TCLIQUE_WEIGHT cliqueweight;
11785 TCLIQUE_STATUS tcliquestatus;
11786 SCIP_VAR** vars;
11787 int* cliquenodes;
11788 int nnodes;
11789 int lct;
11790 int est;
11791 int i;
11792
11793 int ntreenodes;
11794 int ncliquenodes;
11795
11796 /* check if source and sink are connencted */
11797 if( !tcliquegraph->precedencematrix[source][sink] )
11798 return SCIP_OKAY;
11799
11800 nnodes = tcliquegraph->nnodes;
11801 vars = tcliquegraph->vars;
11802
11803 /* reset the weights to zero */
11804 BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11805
11806 /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11807 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11808 est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11809
11810 /* weight all jobs which run for sure between source and sink with their duration */
11811 for( i = 0; i < nnodes; ++i )
11812 {
11813 SCIP_VAR* var;
11814 int duration;
11815
11816 var = vars[i];
11817 assert(var != NULL);
11818
11819 duration = tcliquegraph->durations[i];
11820
11821 if( i == source || i == sink )
11822 {
11823 /* source and sink are not weighted */
11824 tcliquegraph->weights[i] = 0;
11825 }
11826 else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11827 {
11828 /* job i runs after source and before sink */
11829 tcliquegraph->weights[i] = duration;
11830 }
11831 else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11832 && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11833 {
11834 /* job i run in between due the bounds of the start time variables */
11835 tcliquegraph->weights[i] = duration;
11836 }
11837 else
11838 tcliquegraph->weights[i] = 0;
11839 }
11840
11841 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11842
11843 /* find (heuristically) maximum cliques */
11844 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11845 tcliquegraph, tcliqueNewsolClique, NULL,
11846 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11847 10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11848
11849 if( ncliquenodes > 1 )
11850 {
11851 char name[SCIP_MAXSTRLEN];
11852 int distance;
11853
11854 /* construct constraint name */
11855 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11856
11857 /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11858 * duration of the source job
11859 */
11860 distance = cliqueweight + tcliquegraph->durations[source];
11861
11862 SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11863 (*naddconss)++;
11864 }
11865
11866 SCIPfreeBufferArray(scip, &cliquenodes);
11867
11868 return SCIP_OKAY;
11869}
11870
11871/** search for precedence constraints
11872 *
11873 * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11874 * corresponding two jobs
11875 */
11876static
11878 SCIP* scip, /**< SCIP data structure */
11879 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11880 int* naddconss /**< pointer to store the number of added constraints */
11881 )
11882{
11883 int* sources;
11884 int* sinks;
11885 int nconss;
11886 int nnodes;
11887 int nsources;
11888 int nsinks;
11889 int i;
11890
11891 nnodes = tcliquegraph->nnodes;
11892 nconss = 0;
11893
11894 nsources = 0;
11895 nsinks = 0;
11896
11899
11900 /* first collect all sources and sinks */
11901 for( i = 0; i < nnodes; ++i )
11902 {
11903 if( tcliquegraph->ninarcs[i] == 0 )
11904 {
11905 sources[nsources] = i;
11906 nsources++;
11907 }
11908
11909 if( tcliquegraph->ninarcs[i] == 0 )
11910 {
11911 sinks[nsinks] = i;
11912 nsinks++;
11913 }
11914 }
11915
11916 /* compute for each node a minimum distance to each sources and each sink */
11917 for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
11918 {
11919 int j;
11920
11921 for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
11922 {
11923 SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
11924 }
11925
11926 for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
11927 {
11928 SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
11929 }
11930 }
11931
11932 (*naddconss) += nconss;
11933
11934 /* for the statistic we count the number added variable constraints */
11935 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
11936
11937 SCIPfreeBufferArray(scip, &sinks);
11938 SCIPfreeBufferArray(scip, &sources);
11939
11940 return SCIP_OKAY;
11941}
11942
11943/** initialize the assumed durations for each variable */
11944static
11946 SCIP* scip, /**< SCIP data structure */
11947 TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
11948 SCIP_CONS** conss, /**< cumulative constraints */
11949 int nconss /**< number of cumulative constraints */
11950 )
11951{
11952 int c;
11953
11954 /* use the cumulative structure to define the duration we are using for each job */
11955 for( c = 0; c < nconss; ++c )
11956 {
11957 SCIP_CONSDATA* consdata;
11958 SCIP_VAR** vars;
11959 int nvars;
11960 int v;
11961
11962 consdata = SCIPconsGetData(conss[c]);
11963 assert(consdata != NULL);
11964
11965 vars = consdata->vars;
11966 nvars = consdata->nvars;
11967
11968 for( v = 0; v < nvars; ++v )
11969 {
11970 int idx;
11971
11972 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
11973 assert(idx >= 0);
11974
11975 /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
11976 * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
11977 * general this is not the case. Therefore, the question would be which duration should be used?
11978 */
11979 tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
11980 assert(tcliquegraph->durations[idx] > 0);
11981 }
11982 }
11983
11984 return SCIP_OKAY;
11985}
11986
11987/** create tclique graph */
11988static
11990 SCIP* scip, /**< SCIP data structure */
11991 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
11992 )
11993{
11994 SCIP_VAR** vars;
11995 SCIP_HASHMAP* varmap;
11996 SCIP_Bool** precedencematrix;
11997 SCIP_Bool** demandmatrix;
11998 int* ninarcs;
11999 int* noutarcs;
12000 int* durations;
12001 int* weights;
12002 int nvars;
12003 int v;
12004
12005 vars = SCIPgetVars(scip);
12006 nvars = SCIPgetNVars(scip);
12007
12008 /* allocate memory for the tclique graph data structure */
12009 SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12010
12011 /* create the variable mapping hash map */
12012 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12013
12014 /* each active variables get a node in the graph */
12015 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12016
12017 /* allocate memory for the projected variables bound graph and the none overlapping graph */
12018 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12019 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12020
12021 /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12022 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12023 BMSclearMemoryArray(weights, nvars);
12024
12025 /* array to store the number of in arc of the precedence graph */
12026 SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12027 BMSclearMemoryArray(ninarcs, nvars);
12028
12029 /* array to store the number of out arc of the precedence graph */
12030 SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12031 BMSclearMemoryArray(noutarcs, nvars);
12032
12033 /* array to store the used duration for each node */
12034 SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12035 BMSclearMemoryArray(durations, nvars);
12036
12037 for( v = 0; v < nvars; ++v )
12038 {
12039 SCIP_VAR* var;
12040
12041 var = vars[v];
12042 assert(var != NULL);
12043
12044 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12045 BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12046
12047 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12048 BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12049
12050 /* insert all active variables into the garph */
12051 assert(SCIPvarGetProbindex(var) == v);
12052 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12053 }
12054
12055 (*tcliquegraph)->nnodes = nvars;
12056 (*tcliquegraph)->varmap = varmap;
12057 (*tcliquegraph)->precedencematrix = precedencematrix;
12058 (*tcliquegraph)->demandmatrix = demandmatrix;
12059 (*tcliquegraph)->weights = weights;
12060 (*tcliquegraph)->ninarcs = ninarcs;
12061 (*tcliquegraph)->noutarcs = noutarcs;
12062 (*tcliquegraph)->durations = durations;
12063 (*tcliquegraph)->size = nvars;
12064
12065 return SCIP_OKAY;
12066}
12067
12068/** frees the tclique graph */
12069static
12071 SCIP* scip, /**< SCIP data structure */
12072 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12073 )
12074{
12075 int v;
12076
12077 for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12078 {
12079 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12080 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12081 }
12082
12083 SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12084 SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12085 SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12086 SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12087 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12088 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12089 SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12090 SCIPhashmapFree(&(*tcliquegraph)->varmap);
12091
12092 SCIPfreeBuffer(scip, tcliquegraph);
12093}
12094
12095/** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12096 * constrains (disjunctive constraint)
12097 */
12098static
12100 SCIP* scip, /**< SCIP data structure */
12101 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12102 SCIP_CONS** conss, /**< array of cumulative constraints */
12103 int nconss, /**< number of cumulative constraints */
12104 int* naddconss /**< pointer to store the number of added constraints */
12105 )
12106{
12107 TCLIQUE_GRAPH* tcliquegraph;
12108
12109 /* create tclique graph */
12110 SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12111
12112 /* define for each job a duration */
12113 SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12114
12115 /* constuct incompatibility graph */
12116 SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12117
12118 /* search for new precedence constraints */
12119 if( conshdlrdata->detectvarbounds )
12120 {
12121 SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12122 }
12123
12124 /* search for new cumulative constraints */
12125 if( conshdlrdata->detectdisjunctive )
12126 {
12127 SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12128 }
12129
12130 /* free tclique graph data structure */
12131 freeTcliqueGraph(scip, &tcliquegraph);
12132
12133 return SCIP_OKAY;
12134}
12135
12136/** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12137static
12139 SCIP_CONSDATA* consdata /**< cumulative constraint data */
12140 )
12141{
12142 SCIP_VAR** vars;
12143 int nvars;
12144 int v;
12145
12146 if( consdata->validsignature )
12147 return;
12148
12149 vars = consdata->vars;
12150 nvars = consdata->nvars;
12151
12152 for( v = 0; v < nvars; ++v )
12153 {
12154 consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12155 }
12156
12157 consdata->validsignature = TRUE;
12158}
12159
12160/** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12161static
12163{ /*lint --e{715}*/
12164 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12165
12166 assert(consdata != NULL);
12167 assert(0 <= ind1 && ind1 < consdata->nvars);
12168 assert(0 <= ind2 && ind2 < consdata->nvars);
12169
12170 return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12171}
12172
12173/** run a pairwise comparison */
12174static
12176 SCIP* scip, /**< SCIP data structure */
12177 SCIP_CONS** conss, /**< array of cumulative constraints */
12178 int nconss, /**< number of cumulative constraints */
12179 int* ndelconss /**< pointer to store the number of deletedconstraints */
12180 )
12181{
12182 int i;
12183 int j;
12184
12185 for( i = 0; i < nconss; ++i )
12186 {
12187 SCIP_CONSDATA* consdata0;
12188 SCIP_CONS* cons0;
12189
12190 cons0 = conss[i];
12191 assert(cons0 != NULL);
12192
12193 consdata0 = SCIPconsGetData(cons0);
12194 assert(consdata0 != NULL);
12195
12196 consdataCalcSignature(consdata0);
12197 assert(consdata0->validsignature);
12198
12199 for( j = i+1; j < nconss; ++j )
12200 {
12201 SCIP_CONSDATA* consdata1;
12202 SCIP_CONS* cons1;
12203
12204 cons1 = conss[j];
12205 assert(cons1 != NULL);
12206
12207 consdata1 = SCIPconsGetData(cons1);
12208 assert(consdata1 != NULL);
12209
12210 if( consdata0->capacity != consdata1->capacity )
12211 continue;
12212
12213 consdataCalcSignature(consdata1);
12214 assert(consdata1->validsignature);
12215
12216 if( (consdata1->signature & (~consdata0->signature)) == 0 )
12217 {
12218 SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12219 SCIPswapPointers((void**)&cons0, (void**)&cons1);
12220 assert((consdata0->signature & (~consdata1->signature)) == 0);
12221 }
12222
12223 if( (consdata0->signature & (~consdata1->signature)) == 0 )
12224 {
12225 int* perm0;
12226 int* perm1;
12227 int v0;
12228 int v1;
12229
12230 if( consdata0->nvars > consdata1->nvars )
12231 continue;
12232
12233 if( consdata0->hmin < consdata1->hmin )
12234 continue;
12235
12236 if( consdata0->hmax > consdata1->hmax )
12237 continue;
12238
12239 SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12240 SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12241
12242 /* call sorting method */
12243 SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12244 SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12245
12246 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12247 {
12248 SCIP_VAR* var0;
12249 SCIP_VAR* var1;
12250 int idx0;
12251 int idx1;
12252 int comp;
12253
12254 idx0 = perm0[v0];
12255 idx1 = perm1[v1];
12256
12257 var0 = consdata0->vars[idx0];
12258
12259 var1 = consdata1->vars[idx1];
12260
12261 comp = SCIPvarCompare(var0, var1);
12262
12263 if( comp == 0 )
12264 {
12265 int duration0;
12266 int duration1;
12267 int demand0;
12268 int demand1;
12269
12270 demand0 = consdata0->demands[idx0];
12271 duration0 = consdata0->durations[idx0];
12272
12273 demand1 = consdata1->demands[idx1];
12274 duration1 = consdata1->durations[idx1];
12275
12276 if( demand0 != demand1 )
12277 break;
12278
12279 if( duration0 != duration1 )
12280 break;
12281
12282 v0++;
12283 v1++;
12284 }
12285 else if( comp > 0 )
12286 v1++;
12287 else
12288 break;
12289 }
12290
12291 if( v0 == consdata0->nvars )
12292 {
12293 if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12294 {
12295 initializeLocks(consdata1, TRUE);
12296 }
12297
12298 /* coverity[swapped_arguments] */
12299 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12300
12301 SCIP_CALL( SCIPdelCons(scip, cons0) );
12302 (*ndelconss)++;
12303 }
12304
12305 SCIPfreeBufferArray(scip, &perm1);
12306 SCIPfreeBufferArray(scip, &perm0);
12307 }
12308 }
12309 }
12310
12311 return SCIP_OKAY;
12312}
12313
12314/** strengthen the variable bounds using the cumulative condition */
12315static
12317 SCIP* scip, /**< SCIP data structure */
12318 SCIP_CONS* cons, /**< constraint to propagate */
12319 int* nchgbds, /**< pointer to store the number of changed bounds */
12320 int* naddconss /**< pointer to store the number of added constraints */
12321 )
12322{
12323 SCIP_CONSDATA* consdata;
12324 SCIP_VAR** vars;
12325 int* durations;
12326 int* demands;
12327 int capacity;
12328 int nvars;
12329 int nconss;
12330 int i;
12331
12332 consdata = SCIPconsGetData(cons);
12333 assert(consdata != NULL);
12334
12335 /* check if the variable bounds got already strengthen by the cumulative constraint */
12336 if( consdata->varbounds )
12337 return SCIP_OKAY;
12338
12339 vars = consdata->vars;
12340 durations = consdata->durations;
12341 demands = consdata->demands;
12342 capacity = consdata->capacity;
12343 nvars = consdata->nvars;
12344
12345 nconss = 0;
12346
12347 for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12348 {
12349 SCIP_VAR** vbdvars;
12350 SCIP_VAR* var;
12351 SCIP_Real* vbdcoefs;
12352 SCIP_Real* vbdconsts;
12353 int nvbdvars;
12354 int b;
12355 int j;
12356
12357 var = consdata->vars[i];
12358 assert(var != NULL);
12359
12360 vbdvars = SCIPvarGetVlbVars(var);
12361 vbdcoefs = SCIPvarGetVlbCoefs(var);
12362 vbdconsts = SCIPvarGetVlbConstants(var);
12363 nvbdvars = SCIPvarGetNVlbs(var);
12364
12365 for( b = 0; b < nvbdvars; ++b )
12366 {
12367 if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12368 {
12369 if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12370 {
12371 for( j = 0; j < nvars; ++j )
12372 {
12373 if( vars[j] == vbdvars[b] )
12374 break;
12375 }
12376 if( j == nvars )
12377 continue;
12378
12379 if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12380 {
12381 SCIP_Bool infeasible;
12382 char name[SCIP_MAXSTRLEN];
12383 int nlocalbdchgs;
12384
12385 SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12386
12387 /* construct constraint name */
12388 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12389
12390 SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12391 nconss++;
12392
12393 SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12394 assert(!infeasible);
12395
12396 (*nchgbds) += nlocalbdchgs;
12397 }
12398 }
12399 }
12400 }
12401 }
12402
12403 (*naddconss) += nconss;
12404
12405 consdata->varbounds = TRUE;
12406
12407 return SCIP_OKAY;
12408}
12409
12410/** helper function to enforce constraints */
12411static
12413 SCIP* scip, /**< SCIP data structure */
12414 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12415 SCIP_CONS** conss, /**< constraints to process */
12416 int nconss, /**< number of constraints */
12417 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12418 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12419 SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12420 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12421 )
12422{
12423 SCIP_CONSHDLRDATA* conshdlrdata;
12424
12425 assert(conshdlr != NULL);
12426 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12427 assert(nconss == 0 || conss != NULL);
12428 assert(result != NULL);
12429
12430 if( solinfeasible )
12431 {
12432 *result = SCIP_INFEASIBLE;
12433 return SCIP_OKAY;
12434 }
12435
12436 SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12437 sol == NULL ? "LP" : "relaxation");
12438
12439 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12440 assert(conshdlrdata != NULL);
12441
12442 (*result) = SCIP_FEASIBLE;
12443
12444 if( conshdlrdata->usebinvars )
12445 {
12446 SCIP_Bool separated;
12447 SCIP_Bool cutoff;
12448 int c;
12449
12450 separated = FALSE;
12451
12452 /* first check if a constraints is violated */
12453 for( c = 0; c < nusefulconss; ++c )
12454 {
12455 SCIP_CONS* cons;
12456 SCIP_Bool violated;
12457
12458 cons = conss[c];
12459 assert(cons != NULL);
12460
12461 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12462
12463 if( !violated )
12464 continue;
12465
12466 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12467 if ( cutoff )
12468 {
12469 *result = SCIP_CUTOFF;
12470 return SCIP_OKAY;
12471 }
12472 }
12473
12474 for( ; c < nconss && !separated; ++c )
12475 {
12476 SCIP_CONS* cons;
12477 SCIP_Bool violated;
12478
12479 cons = conss[c];
12480 assert(cons != NULL);
12481
12482 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12483
12484 if( !violated )
12485 continue;
12486
12487 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12488 if ( cutoff )
12489 {
12490 *result = SCIP_CUTOFF;
12491 return SCIP_OKAY;
12492 }
12493 }
12494
12495 if( separated )
12496 (*result) = SCIP_SEPARATED;
12497 }
12498 else
12499 {
12500 SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12501 }
12502
12503 return SCIP_OKAY;
12504}
12505
12506/**@} */
12507
12508
12509/**@name Callback methods of constraint handler
12510 *
12511 * @{
12512 */
12513
12514/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12515static
12516SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12517{ /*lint --e{715}*/
12518 assert(scip != NULL);
12519 assert(conshdlr != NULL);
12520 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12521
12522 /* call inclusion method of constraint handler */
12524
12526
12527 *valid = TRUE;
12528
12529 return SCIP_OKAY;
12530}
12531
12532/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12533static
12534SCIP_DECL_CONSFREE(consFreeCumulative)
12535{ /*lint --e{715}*/
12536 SCIP_CONSHDLRDATA* conshdlrdata;
12537
12538 assert(conshdlr != NULL);
12539 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12540
12541 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12542 assert(conshdlrdata != NULL);
12543
12544#ifdef SCIP_STATISTIC
12545 if( !conshdlrdata->iscopy )
12546 {
12547 /* statisitc output if SCIP_STATISTIC is defined */
12548 SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12549 conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12550 SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12551 conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12552 SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12553 conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12554 }
12555#endif
12556
12557 conshdlrdataFree(scip, &conshdlrdata);
12558
12559 SCIPconshdlrSetData(conshdlr, NULL);
12560
12561 return SCIP_OKAY;
12562}
12563
12564
12565/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12566static
12567SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12568{ /*lint --e{715}*/
12569 SCIP_CONSHDLRDATA* conshdlrdata;
12570 int c;
12571
12572 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12573 assert(conshdlrdata != NULL);
12574
12575 conshdlrdata->detectedredundant = FALSE;
12576
12577 for( c = 0; c < nconss; ++c )
12578 {
12579 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12580 * hmax)
12581 */
12582 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12583 }
12584
12585 return SCIP_OKAY;
12586}
12587
12588
12589/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12590#ifdef SCIP_STATISTIC
12591static
12592SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12593{ /*lint --e{715}*/
12594 SCIP_CONSHDLRDATA* conshdlrdata;
12595 int c;
12596
12597 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12598 assert(conshdlrdata != NULL);
12599
12600 for( c = 0; c < nconss; ++c )
12601 {
12602 SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12603
12604#ifdef SCIP_DISABLED_CODE
12606#endif
12607 }
12608
12609 if( !conshdlrdata->iscopy )
12610 {
12611 SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12612 SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12613 SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12614 SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12615 SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12616 SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12617 SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12618 SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12619 SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12620 }
12621
12622 return SCIP_OKAY;
12623}
12624#endif
12625
12626
12627/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12628static
12629SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12630{ /*lint --e{715}*/
12631 SCIP_CONSDATA* consdata;
12632 int c;
12633
12634 assert(conshdlr != NULL);
12635 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12636
12637 /* release the rows of all constraints */
12638 for( c = 0; c < nconss; ++c )
12639 {
12640 consdata = SCIPconsGetData(conss[c]);
12641 assert(consdata != NULL);
12642
12643 /* free rows */
12644 SCIP_CALL( consdataFreeRows(scip, &consdata) );
12645 }
12646
12647 return SCIP_OKAY;
12648}
12649
12650/** frees specific constraint data */
12651static
12652SCIP_DECL_CONSDELETE(consDeleteCumulative)
12653{ /*lint --e{715}*/
12654 assert(conshdlr != NULL);
12655 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12656 assert(consdata != NULL );
12657 assert(*consdata != NULL );
12658
12659 /* if constraint belongs to transformed problem space, drop bound change events on variables */
12660 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12661 {
12662 SCIP_CONSHDLRDATA* conshdlrdata;
12663
12664 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12665 assert(conshdlrdata != NULL);
12666
12667 SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12668 }
12669
12670 /* free cumulative constraint data */
12671 SCIP_CALL( consdataFree(scip, consdata) );
12672
12673 return SCIP_OKAY;
12674}
12675
12676/** transforms constraint data into data belonging to the transformed problem */
12677static
12678SCIP_DECL_CONSTRANS(consTransCumulative)
12679{ /*lint --e{715}*/
12680 SCIP_CONSHDLRDATA* conshdlrdata;
12681 SCIP_CONSDATA* sourcedata;
12682 SCIP_CONSDATA* targetdata;
12683
12684 assert(conshdlr != NULL);
12686 assert(sourcecons != NULL);
12687 assert(targetcons != NULL);
12688
12689 sourcedata = SCIPconsGetData(sourcecons);
12690 assert(sourcedata != NULL);
12691 assert(sourcedata->demandrows == NULL);
12692
12693 SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12694
12695 /* get event handler */
12696 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12697 assert(conshdlrdata != NULL);
12698 assert(conshdlrdata->eventhdlr != NULL);
12699
12700 /* create constraint data for target constraint */
12701 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12702 sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12703 sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12704
12705 /* create target constraint */
12706 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12707 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12708 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12709 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12710 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12711
12712 /* catch bound change events of variables */
12713 SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12714
12715 return SCIP_OKAY;
12716}
12717
12718/** LP initialization method of constraint handler */
12719static
12720SCIP_DECL_CONSINITLP(consInitlpCumulative)
12721{
12722 SCIP_CONSHDLRDATA* conshdlrdata;
12723 int c;
12724
12725 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12726 assert(conshdlr != NULL);
12727 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12728 assert(conshdlrdata != NULL);
12729
12730 *infeasible = FALSE;
12731
12732 SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12733
12734 if( conshdlrdata->usebinvars )
12735 {
12736 /* add rows to LP */
12737 for( c = 0; c < nconss && !(*infeasible); ++c )
12738 {
12739 assert(SCIPconsIsInitial(conss[c]));
12740 SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12741
12742 if( conshdlrdata->cutsasconss )
12743 {
12745 }
12746 }
12747 }
12748
12749 /**@todo if we want to use only the integer variables; only these will be in cuts
12750 * create some initial cuts, currently these are only separated */
12751
12752 return SCIP_OKAY;
12753}
12754
12755/** separation method of constraint handler for LP solutions */
12756static
12757SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12758{
12759 SCIP_CONSHDLRDATA* conshdlrdata;
12760 SCIP_Bool cutoff;
12761 SCIP_Bool separated;
12762 int c;
12763
12764 SCIPdebugMsg(scip, "consSepalpCumulative\n");
12765
12766 assert(conshdlr != NULL);
12767 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12768 assert(nconss == 0 || conss != NULL);
12769 assert(result != NULL);
12770 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12771 assert(conshdlrdata != NULL);
12772
12773 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12774
12775 cutoff = FALSE;
12776 separated = FALSE;
12777 (*result) = SCIP_DIDNOTRUN;
12778
12779 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12780 return SCIP_OKAY;
12781
12782 (*result) = SCIP_DIDNOTFIND;
12783
12784 if( conshdlrdata->usebinvars )
12785 {
12786 /* check all useful cumulative constraints for feasibility */
12787 for( c = 0; c < nusefulconss && !cutoff; ++c )
12788 {
12789 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12790 }
12791
12792 if( !cutoff && conshdlrdata->usecovercuts )
12793 {
12794 for( c = 0; c < nusefulconss; ++c )
12795 {
12796 SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12797 }
12798 }
12799 }
12800
12801 if( conshdlrdata->sepaold )
12802 {
12803 /* separate cuts containing only integer variables */
12804 for( c = 0; c < nusefulconss; ++c )
12805 {
12806 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12807 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12808 }
12809 }
12810
12811 if( cutoff )
12812 *result = SCIP_CUTOFF;
12813 else if( separated )
12814 *result = SCIP_SEPARATED;
12815
12816 return SCIP_OKAY;
12817}
12818
12819/** separation method of constraint handler for arbitrary primal solutions */
12820static
12821SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12822{ /*lint --e{715}*/
12823 SCIP_CONSHDLRDATA* conshdlrdata;
12824 SCIP_Bool cutoff;
12825 SCIP_Bool separated;
12826 int c;
12827
12828 assert(conshdlr != NULL);
12829 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12830 assert(nconss == 0 || conss != NULL);
12831 assert(result != NULL);
12832
12833 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12834 assert(conshdlrdata != NULL);
12835
12836 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12837 return SCIP_OKAY;
12838
12839 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12840
12841 cutoff = FALSE;
12842 separated = FALSE;
12843 (*result) = SCIP_DIDNOTFIND;
12844
12845 if( conshdlrdata->usebinvars )
12846 {
12847 /* check all useful cumulative constraints for feasibility */
12848 for( c = 0; c < nusefulconss && !cutoff; ++c )
12849 {
12850 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12851 }
12852
12853 if( !cutoff && conshdlrdata->usecovercuts )
12854 {
12855 for( c = 0; c < nusefulconss; ++c )
12856 {
12857 SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12858 }
12859 }
12860 }
12861 if( conshdlrdata->sepaold )
12862 {
12863 /* separate cuts containing only integer variables */
12864 for( c = 0; c < nusefulconss; ++c )
12865 {
12866 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12867 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12868 }
12869 }
12870
12871 if( cutoff )
12872 *result = SCIP_CUTOFF;
12873 else if( separated )
12874 *result = SCIP_SEPARATED;
12875
12876 return SCIP_OKAY;
12877}
12878
12879/** constraint enforcing method of constraint handler for LP solutions */
12880static
12881SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12882{ /*lint --e{715}*/
12883 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12884
12885 return SCIP_OKAY;
12886}
12887
12888/** constraint enforcing method of constraint handler for relaxation solutions */
12889static
12890SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
12891{ /*lint --e{715}*/
12892 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12893
12894 return SCIP_OKAY;
12895}
12896
12897/** constraint enforcing method of constraint handler for pseudo solutions */
12898static
12899SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12900{ /*lint --e{715}*/
12901 SCIP_CONSHDLRDATA* conshdlrdata;
12902
12903 SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
12904
12905 assert(conshdlr != NULL);
12906 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12907 assert(nconss == 0 || conss != NULL);
12908 assert(result != NULL);
12909
12910 if( objinfeasible )
12911 {
12912 *result = SCIP_DIDNOTRUN;
12913 return SCIP_OKAY;
12914 }
12915
12916 (*result) = SCIP_FEASIBLE;
12917
12918 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12919 assert(conshdlrdata != NULL);
12920
12921 SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
12922
12923 return SCIP_OKAY;
12924}
12925
12926/** feasibility check method of constraint handler for integral solutions */
12927static
12928SCIP_DECL_CONSCHECK(consCheckCumulative)
12929{ /*lint --e{715}*/
12930 int c;
12931
12932 assert(conshdlr != NULL);
12933 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12934 assert(nconss == 0 || conss != NULL);
12935 assert(result != NULL);
12936
12937 *result = SCIP_FEASIBLE;
12938
12939 SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
12940
12941 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
12942 {
12943 SCIP_Bool violated = FALSE;
12944
12945 SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
12946
12947 if( violated )
12948 *result = SCIP_INFEASIBLE;
12949 }
12950
12951 return SCIP_OKAY;
12952}
12953
12954/** domain propagation method of constraint handler */
12955static
12956SCIP_DECL_CONSPROP(consPropCumulative)
12957{ /*lint --e{715}*/
12958 SCIP_CONSHDLRDATA* conshdlrdata;
12959 SCIP_Bool cutoff;
12960 int nchgbds;
12961 int ndelconss;
12962 int c;
12963
12964 SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
12965
12966 assert(conshdlr != NULL);
12967 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12968 assert(nconss == 0 || conss != NULL);
12969 assert(result != NULL);
12970
12971 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12972 assert(conshdlrdata != NULL);
12973
12974 nchgbds = 0;
12975 ndelconss = 0;
12976 cutoff = FALSE;
12977 (*result) = SCIP_DIDNOTRUN;
12978
12979 /* propgate all useful constraints */
12980 for( c = 0; c < nusefulconss && !cutoff; ++c )
12981 {
12982 SCIP_CONS* cons;
12983
12984 cons = conss[c];
12985 assert(cons != NULL);
12986
12987 if( SCIPgetDepth(scip) == 0 )
12988 {
12990 &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
12991
12992 if( cutoff )
12993 break;
12994
12995 if( SCIPconsIsDeleted(cons) )
12996 continue;
12997 }
12998
12999 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13000 }
13001
13002 if( !cutoff && nchgbds == 0 )
13003 {
13004 /* propgate all other constraints */
13005 for( c = nusefulconss; c < nconss && !cutoff; ++c )
13006 {
13007 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13008 }
13009 }
13010
13011 if( cutoff )
13012 {
13013 SCIPdebugMsg(scip, "detected infeasible\n");
13014 *result = SCIP_CUTOFF;
13015 }
13016 else if( nchgbds > 0 )
13017 {
13018 SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13019 *result = SCIP_REDUCEDDOM;
13020 }
13021 else
13022 *result = SCIP_DIDNOTFIND;
13023
13024 return SCIP_OKAY;
13025}
13026
13027/** presolving method of constraint handler */
13028static
13029SCIP_DECL_CONSPRESOL(consPresolCumulative)
13030{ /*lint --e{715}*/
13031 SCIP_CONSHDLRDATA* conshdlrdata;
13032 SCIP_CONS* cons;
13033 SCIP_Bool cutoff;
13034 SCIP_Bool unbounded;
13035 int oldnfixedvars;
13036 int oldnchgbds;
13037 int oldndelconss;
13038 int oldnaddconss;
13039 int oldnupgdconss;
13040 int oldnchgsides;
13041 int oldnchgcoefs;
13042 int c;
13043
13044 assert(conshdlr != NULL);
13045 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13046 assert(scip != NULL);
13047 assert(result != NULL);
13048
13049 SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13050
13051 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13052 assert(conshdlrdata != NULL);
13053
13054 *result = SCIP_DIDNOTRUN;
13055
13056 oldnfixedvars = *nfixedvars;
13057 oldnchgbds = *nchgbds;
13058 oldnchgsides = *nchgsides;
13059 oldnchgcoefs = *nchgcoefs;
13060 oldnupgdconss = *nupgdconss;
13061 oldndelconss = *ndelconss;
13062 oldnaddconss = *naddconss;
13063 cutoff = FALSE;
13064 unbounded = FALSE;
13065
13066 /* process constraints */
13067 for( c = 0; c < nconss && !cutoff; ++c )
13068 {
13069 cons = conss[c];
13070
13071 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13072 * hmax)
13073 */
13074 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13075
13076 if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13077 {
13078 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13079 nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13080
13081 if( cutoff || unbounded )
13082 break;
13083
13084 if( SCIPconsIsDeleted(cons) )
13085 continue;
13086 }
13087
13088 /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13089 if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13090 {
13091 SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13092 }
13093
13094 /* strengthen existing variable bounds using the cumulative condition */
13095 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13096 {
13097 SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13098 }
13099
13100 /* propagate cumulative constraint */
13101 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13102 assert(checkDemands(scip, cons) || cutoff);
13103 }
13104
13105 if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13106 {
13107 SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13108 }
13109
13110 /* only perform the detection of variable bounds and disjunctive constraint once */
13111 if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13112 && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13113 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13114 {
13115 /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13116 * propagation
13117 */
13118 SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13119 conshdlrdata->detectedredundant = TRUE;
13120 }
13121
13122 if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13123 {
13124 SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13125 }
13126
13127 SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13128 *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13129
13130 if( cutoff )
13131 *result = SCIP_CUTOFF;
13132 else if( unbounded )
13133 *result = SCIP_UNBOUNDED;
13134 else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13135 || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13136 *result = SCIP_SUCCESS;
13137 else
13138 *result = SCIP_DIDNOTFIND;
13139
13140 return SCIP_OKAY;
13141}
13142
13143/** propagation conflict resolving method of constraint handler */
13144static
13145SCIP_DECL_CONSRESPROP(consRespropCumulative)
13146{ /*lint --e{715}*/
13147 SCIP_CONSHDLRDATA* conshdlrdata;
13148 SCIP_CONSDATA* consdata;
13149
13150 assert(conshdlr != NULL);
13151 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13152 assert(scip != NULL);
13153 assert(result != NULL);
13154 assert(infervar != NULL);
13155 assert(bdchgidx != NULL);
13156
13157 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13158 assert(conshdlrdata != NULL);
13159
13160 /* process constraint */
13161 assert(cons != NULL);
13162
13163 consdata = SCIPconsGetData(cons);
13164 assert(consdata != NULL);
13165
13166 SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13167 SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13169
13170 SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13171 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13172 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13173
13174 return SCIP_OKAY;
13175}
13176
13177/** variable rounding lock method of constraint handler */
13178static
13179SCIP_DECL_CONSLOCK(consLockCumulative)
13180{ /*lint --e{715}*/
13181 SCIP_CONSDATA* consdata;
13182 SCIP_VAR** vars;
13183 int v;
13184
13185 SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13186
13187 assert(scip != NULL);
13188 assert(cons != NULL);
13189 assert(locktype == SCIP_LOCKTYPE_MODEL);
13190
13191 consdata = SCIPconsGetData(cons);
13192 assert(consdata != NULL);
13193
13194 vars = consdata->vars;
13195 assert(vars != NULL);
13196
13197 for( v = 0; v < consdata->nvars; ++v )
13198 {
13199 if( consdata->downlocks[v] && consdata->uplocks[v] )
13200 {
13201 /* the integer start variable should not get rounded in both direction */
13202 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13203 }
13204 else if( consdata->downlocks[v] )
13205 {
13206 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13207 }
13208 else if( consdata->uplocks[v] )
13209 {
13210 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13211 }
13212 }
13213
13214 return SCIP_OKAY;
13215}
13216
13217
13218/** constraint display method of constraint handler */
13219static
13220SCIP_DECL_CONSPRINT(consPrintCumulative)
13221{ /*lint --e{715}*/
13222 assert(scip != NULL);
13223 assert(conshdlr != NULL);
13224 assert(cons != NULL);
13225
13226 consdataPrint(scip, SCIPconsGetData(cons), file);
13227
13228 return SCIP_OKAY;
13229}
13230
13231/** constraint copying method of constraint handler */
13232static
13233SCIP_DECL_CONSCOPY(consCopyCumulative)
13234{ /*lint --e{715}*/
13235 SCIP_CONSDATA* sourceconsdata;
13236 SCIP_VAR** sourcevars;
13237 SCIP_VAR** vars;
13238 const char* consname;
13239
13240 int nvars;
13241 int v;
13242
13243 sourceconsdata = SCIPconsGetData(sourcecons);
13244 assert(sourceconsdata != NULL);
13245
13246 /* get variables of the source constraint */
13247 nvars = sourceconsdata->nvars;
13248 sourcevars = sourceconsdata->vars;
13249
13250 (*valid) = TRUE;
13251
13252 if( nvars == 0 )
13253 return SCIP_OKAY;
13254
13255 /* allocate buffer array */
13256 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13257
13258 for( v = 0; v < nvars && *valid; ++v )
13259 {
13260 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13261 assert(!(*valid) || vars[v] != NULL);
13262 }
13263
13264 /* only create the target constraint, if all variables could be copied */
13265 if( *valid )
13266 {
13267 if( name != NULL )
13268 consname = name;
13269 else
13270 consname = SCIPconsGetName(sourcecons);
13271
13272 /* create a copy of the cumulative constraint */
13273 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13274 sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13275 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13276
13277 /* adjust left side if the time axis if needed */
13278 if( sourceconsdata->hmin > 0 )
13279 {
13280 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13281 }
13282
13283 /* adjust right side if the time axis if needed */
13284 if( sourceconsdata->hmax < INT_MAX )
13285 {
13286 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13287 }
13288 }
13289
13290 /* free buffer array */
13291 SCIPfreeBufferArray(scip, &vars);
13292
13293 return SCIP_OKAY;
13294}
13295
13296
13297/** constraint parsing method of constraint handler */
13298static
13299SCIP_DECL_CONSPARSE(consParseCumulative)
13300{ /*lint --e{715}*/
13301 SCIP_VAR** vars;
13302 SCIP_VAR* var;
13303 SCIP_Real value;
13304 char strvalue[SCIP_MAXSTRLEN];
13305 char* endptr;
13306 int* demands;
13307 int* durations;
13308 int capacity;
13309 int duration;
13310 int demand;
13311 int hmin;
13312 int hmax;
13313 int varssize;
13314 int nvars;
13315
13316 SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13317
13318 *success = TRUE;
13319
13320 /* cutoff "cumulative" form the constraint string */
13321 SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13322 str = endptr;
13323
13324 varssize = 100;
13325 nvars = 0;
13326
13327 /* allocate buffer array for variables */
13328 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13329 SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13330 SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13331
13332 do
13333 {
13334 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13335
13336 if( var == NULL )
13337 {
13338 endptr = strchr(endptr, ')');
13339
13340 if( endptr == NULL )
13341 *success = FALSE;
13342 else
13343 str = endptr;
13344
13345 break;
13346 }
13347
13348 str = endptr;
13349 SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13350 duration = atoi(strvalue);
13351 str = endptr;
13352
13353 SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13354 demand = atoi(strvalue);
13355 str = endptr;
13356
13357 SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13358
13359 vars[nvars] = var;
13360 demands[nvars] = demand;
13361 durations[nvars] = duration;
13362 nvars++;
13363 }
13364 while( *str != ')' );
13365
13366 if( *success )
13367 {
13368 /* parse effective time window */
13369 SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13370 hmin = atoi(strvalue);
13371 str = endptr;
13372
13373 if( SCIPparseReal(scip, str, &value, &endptr) )
13374 {
13375 hmax = (int)(value);
13376 str = endptr;
13377
13378 /* parse capacity */
13379 SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13380 str = endptr;
13381 if( SCIPparseReal(scip, str, &value, &endptr) )
13382 {
13383 capacity = (int)value;
13384
13385 /* create cumulative constraint */
13386 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13387 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13388
13389 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13390 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13391 }
13392 }
13393 }
13394
13395 /* free buffer arrays */
13396 SCIPfreeBufferArray(scip, &durations);
13397 SCIPfreeBufferArray(scip, &demands);
13398 SCIPfreeBufferArray(scip, &vars);
13399
13400 return SCIP_OKAY;
13401}
13402
13403
13404/** constraint method of constraint handler which returns the variables (if possible) */
13405static
13406SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13407{ /*lint --e{715}*/
13408 SCIP_CONSDATA* consdata;
13409
13410 consdata = SCIPconsGetData(cons);
13411 assert(consdata != NULL);
13412
13413 if( varssize < consdata->nvars )
13414 (*success) = FALSE;
13415 else
13416 {
13417 assert(vars != NULL);
13418
13419 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13420 (*success) = TRUE;
13421 }
13422
13423 return SCIP_OKAY;
13424}
13425
13426/** constraint method of constraint handler which returns the number of variables (if possible) */
13427static
13428SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13429{ /*lint --e{715}*/
13430 SCIP_CONSDATA* consdata;
13431
13432 consdata = SCIPconsGetData(cons);
13433 assert(consdata != NULL);
13434
13435 (*nvars) = consdata->nvars;
13436 (*success) = TRUE;
13437
13438 return SCIP_OKAY;
13439}
13440
13441/**@} */
13442
13443/**@name Callback methods of event handler
13444 *
13445 * @{
13446 */
13447
13448
13449/** execution method of event handler */
13450static
13451SCIP_DECL_EVENTEXEC(eventExecCumulative)
13452{ /*lint --e{715}*/
13453 SCIP_CONSDATA* consdata;
13454
13455 assert(scip != NULL);
13456 assert(eventhdlr != NULL);
13457 assert(eventdata != NULL);
13458 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13459 assert(event != NULL);
13460
13461 consdata = (SCIP_CONSDATA*)eventdata;
13462 assert(consdata != NULL);
13463
13464 /* mark the constraint to be not propagated */
13465 consdata->propagated = FALSE;
13466
13467 return SCIP_OKAY;
13468}
13469
13470/**@} */
13471
13472/*
13473 * constraint specific interface methods
13474 */
13475
13476/** creates the handler for cumulative constraints and includes it in SCIP */
13478 SCIP* scip /**< SCIP data structure */
13479 )
13480{
13481 SCIP_CONSHDLRDATA* conshdlrdata;
13482 SCIP_CONSHDLR* conshdlr;
13483 SCIP_EVENTHDLR* eventhdlr;
13484
13485 /* create event handler for bound change events */
13486 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13487
13488 /* create cumulative constraint handler data */
13489 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13490
13491 /* include constraint handler */
13494 consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13495 conshdlrdata) );
13496
13497 assert(conshdlr != NULL);
13498
13499 /* set non-fundamental callbacks via specific setter functions */
13500 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13501 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13502#ifdef SCIP_STATISTIC
13503 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13504#endif
13505 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13506 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13507 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13508 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13509 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13510 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13511 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13512 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13514 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13517 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13518 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13520 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13521 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13522
13523 /* add cumulative constraint handler parameters */
13525 "constraints/" CONSHDLR_NAME "/ttinfer",
13526 "should time-table (core-times) propagator be used to infer bounds?",
13527 &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13529 "constraints/" CONSHDLR_NAME "/efcheck",
13530 "should edge-finding be used to detect an overload?",
13531 &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13533 "constraints/" CONSHDLR_NAME "/efinfer",
13534 "should edge-finding be used to infer bounds?",
13535 &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13537 "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13538 &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13540 "constraints/" CONSHDLR_NAME "/ttefcheck",
13541 "should time-table edge-finding be used to detect an overload?",
13542 &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13544 "constraints/" CONSHDLR_NAME "/ttefinfer",
13545 "should time-table edge-finding be used to infer bounds?",
13546 &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13547
13549 "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13550 &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13552 "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13553 &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13555 "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13556 &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13558 "constraints/" CONSHDLR_NAME "/cutsasconss",
13559 "should the cumulative constraint create cuts as knapsack constraints?",
13560 &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13562 "constraints/" CONSHDLR_NAME "/sepaold",
13563 "shall old sepa algo be applied?",
13564 &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13565
13567 "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13568 &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13569
13570 /* presolving parameters */
13572 "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13573 &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13575 "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13576 &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13578 "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13579 &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13581 "constraints/" CONSHDLR_NAME "/presolpairwise",
13582 "should pairwise constraint comparison be performed in presolving?",
13583 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13585 "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13586 &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13587
13589 "constraints/" CONSHDLR_NAME "/maxnodes",
13590 "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13591 &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13593 "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13594 &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13596 "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13597 &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13598
13599 /* conflict analysis parameters */
13601 "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13602 &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13603
13604 return SCIP_OKAY;
13605}
13606
13607/** creates and captures a cumulative constraint */
13609 SCIP* scip, /**< SCIP data structure */
13610 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13611 const char* name, /**< name of constraint */
13612 int nvars, /**< number of variables (jobs) */
13613 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13614 int* durations, /**< array containing corresponding durations */
13615 int* demands, /**< array containing corresponding demands */
13616 int capacity, /**< available cumulative capacity */
13617 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13618 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13619 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13620 * Usually set to TRUE. */
13621 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13622 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13623 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13624 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13625 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13626 * Usually set to TRUE. */
13627 SCIP_Bool local, /**< is constraint only valid locally?
13628 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13629 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13630 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13631 * adds coefficients to this constraint. */
13632 SCIP_Bool dynamic, /**< is constraint subject to aging?
13633 * Usually set to FALSE. Set to TRUE for own cuts which
13634 * are seperated as constraints. */
13635 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13636 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13637 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13638 * if it may be moved to a more global node?
13639 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13640 )
13641{
13642 SCIP_CONSHDLR* conshdlr;
13643 SCIP_CONSDATA* consdata;
13644
13645 assert(scip != NULL);
13646
13647 /* find the cumulative constraint handler */
13648 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13649 if( conshdlr == NULL )
13650 {
13651 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13652 return SCIP_PLUGINNOTFOUND;
13653 }
13654
13655 SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13656
13657 /* create constraint data */
13658 SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13659
13660 /* create constraint */
13661 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13662 initial, separate, enforce, check, propagate,
13663 local, modifiable, dynamic, removable, stickingatnode) );
13664
13666 {
13667 SCIP_CONSHDLRDATA* conshdlrdata;
13668
13669 /* get event handler */
13670 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13671 assert(conshdlrdata != NULL);
13672 assert(conshdlrdata->eventhdlr != NULL);
13673
13674 /* catch bound change events of variables */
13675 SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13676 }
13677
13678 return SCIP_OKAY;
13679}
13680
13681/** creates and captures a cumulative constraint
13682 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13683 * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13684 *
13685 * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13686 *
13687 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13688 */
13690 SCIP* scip, /**< SCIP data structure */
13691 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13692 const char* name, /**< name of constraint */
13693 int nvars, /**< number of variables (jobs) */
13694 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13695 int* durations, /**< array containing corresponding durations */
13696 int* demands, /**< array containing corresponding demands */
13697 int capacity /**< available cumulative capacity */
13698 )
13699{
13700 assert(scip != NULL);
13701
13702 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13704
13705 return SCIP_OKAY;
13706}
13707
13708/** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13710 SCIP* scip, /**< SCIP data structure */
13711 SCIP_CONS* cons, /**< constraint data */
13712 int hmin /**< left bound of time axis to be considered */
13713 )
13714{
13715 SCIP_CONSDATA* consdata;
13716 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13717 {
13718 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13719 return SCIP_INVALIDCALL;
13720 }
13721
13722 consdata = SCIPconsGetData(cons);
13723 assert(consdata != NULL);
13724 assert(hmin >= 0);
13725 assert(hmin <= consdata->hmax);
13726
13727 consdata->hmin = hmin;
13728
13729 return SCIP_OKAY;
13730}
13731
13732/** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13734 SCIP* scip, /**< SCIP data structure */
13735 SCIP_CONS* cons /**< constraint */
13736 )
13737{
13738 SCIP_CONSDATA* consdata;
13739 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13740 {
13741 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13742 SCIPABORT();
13743 return 0; /*lint !e527*/
13744 }
13745
13746 consdata = SCIPconsGetData(cons);
13747 assert(consdata != NULL);
13748
13749 return consdata->hmin;
13750}
13751
13752/** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13754 SCIP* scip, /**< SCIP data structure */
13755 SCIP_CONS* cons, /**< constraint data */
13756 int hmax /**< right 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 SCIPABORT();
13764 return SCIP_INVALIDCALL; /*lint !e527*/
13765 }
13766
13767 consdata = SCIPconsGetData(cons);
13768 assert(consdata != NULL);
13769 assert(hmax >= consdata->hmin);
13770
13771 consdata->hmax = hmax;
13772
13773 return SCIP_OKAY;
13774}
13775
13776/** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13778 SCIP* scip, /**< SCIP data structure */
13779 SCIP_CONS* cons /**< constraint */
13780 )
13781{
13782 SCIP_CONSDATA* consdata;
13783 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13784 {
13785 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13786 SCIPABORT();
13787 return 0; /*lint !e527*/
13788 }
13789
13790 consdata = SCIPconsGetData(cons);
13791 assert(consdata != NULL);
13792
13793 return consdata->hmax;
13794}
13795
13796/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13798 SCIP* scip, /**< SCIP data structure */
13799 SCIP_CONS* cons /**< constraint data */
13800 )
13801{
13802 SCIP_CONSDATA* consdata;
13803
13804 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13805 {
13806 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13807 SCIPABORT();
13808 return NULL; /*lint !e527*/
13809 }
13810
13811 consdata = SCIPconsGetData(cons);
13812 assert(consdata != NULL);
13813
13814 return consdata->vars;
13815}
13816
13817/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13819 SCIP* scip, /**< SCIP data structure */
13820 SCIP_CONS* cons /**< constraint data */
13821 )
13822{
13823 SCIP_CONSDATA* consdata;
13824
13825 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13826 {
13827 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13828 SCIPABORT();
13829 return -1; /*lint !e527*/
13830 }
13831
13832 consdata = SCIPconsGetData(cons);
13833 assert(consdata != NULL);
13834
13835 return consdata->nvars;
13836}
13837
13838/** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13840 SCIP* scip, /**< SCIP data structure */
13841 SCIP_CONS* cons /**< constraint data */
13842 )
13843{
13844 SCIP_CONSDATA* consdata;
13845
13846 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13847 {
13848 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13849 SCIPABORT();
13850 return -1; /*lint !e527*/
13851 }
13852
13853 consdata = SCIPconsGetData(cons);
13854 assert(consdata != NULL);
13855
13856 return consdata->capacity;
13857}
13858
13859/** returns the durations of the cumulative constraint */ /*lint -e{715}*/
13861 SCIP* scip, /**< SCIP data structure */
13862 SCIP_CONS* cons /**< constraint data */
13863 )
13864{
13865 SCIP_CONSDATA* consdata;
13866
13867 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13868 {
13869 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13870 SCIPABORT();
13871 return NULL; /*lint !e527*/
13872 }
13873
13874 consdata = SCIPconsGetData(cons);
13875 assert(consdata != NULL);
13876
13877 return consdata->durations;
13878}
13879
13880/** returns the demands of the cumulative constraint */ /*lint -e{715}*/
13882 SCIP* scip, /**< SCIP data structure */
13883 SCIP_CONS* cons /**< constraint data */
13884 )
13885{
13886 SCIP_CONSDATA* consdata;
13887
13888 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13889 {
13890 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13891 SCIPABORT();
13892 return NULL; /*lint !e527*/
13893 }
13894
13895 consdata = SCIPconsGetData(cons);
13896 assert(consdata != NULL);
13897
13898 return consdata->demands;
13899}
13900
13901/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
13902 * given solution is satisfied
13903 */
13905 SCIP* scip, /**< SCIP data structure */
13906 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
13907 int nvars, /**< number of variables (jobs) */
13908 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13909 int* durations, /**< array containing corresponding durations */
13910 int* demands, /**< array containing corresponding demands */
13911 int capacity, /**< available cumulative capacity */
13912 int hmin, /**< left bound of time axis to be considered (including hmin) */
13913 int hmax, /**< right bound of time axis to be considered (not including hmax) */
13914 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
13915 SCIP_CONS* cons, /**< constraint which is checked */
13916 SCIP_Bool printreason /**< should the reason for the violation be printed? */
13917 )
13918{
13919 assert(scip != NULL);
13920 assert(violated != NULL);
13921
13922 SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
13923 violated, cons, printreason) );
13924
13925 return SCIP_OKAY;
13926}
13927
13928/** normalize cumulative condition */ /*lint -e{715}*/
13930 SCIP* scip, /**< SCIP data structure */
13931 int nvars, /**< number of start time variables (activities) */
13932 SCIP_VAR** vars, /**< array of start time variables */
13933 int* durations, /**< array of durations */
13934 int* demands, /**< array of demands */
13935 int* capacity, /**< pointer to store the changed cumulative capacity */
13936 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
13937 int* nchgsides /**< pointer to count number of side changes */
13938 )
13939{ /*lint --e{715}*/
13940 normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
13941
13942 return SCIP_OKAY;
13943}
13944
13945/** searches for a time point within the cumulative condition were the cumulative condition can be split */
13947 SCIP* scip, /**< SCIP data structure */
13948 int nvars, /**< number of variables (jobs) */
13949 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13950 int* durations, /**< array containing corresponding durations */
13951 int* demands, /**< array containing corresponding demands */
13952 int capacity, /**< available cumulative capacity */
13953 int* hmin, /**< pointer to store the left bound of the effective horizon */
13954 int* hmax, /**< pointer to store the right bound of the effective horizon */
13955 int* split /**< point were the cumulative condition can be split */
13956 )
13957{
13958 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
13959 hmin, hmax, split) );
13960
13961 return SCIP_OKAY;
13962}
13963
13964/** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
13966 SCIP* scip, /**< SCIP data structure */
13967 int nvars, /**< number of start time variables (activities) */
13968 SCIP_VAR** vars, /**< array of start time variables */
13969 int* durations, /**< array of durations */
13970 int hmin, /**< left bound of time axis to be considered */
13971 int hmax, /**< right bound of time axis to be considered (not including hmax) */
13972 SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
13973 SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
13974 SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
13975 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
13976 int* nfixedvars, /**< pointer to store the number of fixed variables */
13977 int* nchgsides, /**< pointer to store the number of changed sides */
13978 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
13979 )
13980{
13981 if( nvars <= 1 )
13982 return SCIP_OKAY;
13983
13984 /* presolve constraint form the earlier start time point of view */
13985 SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
13986 irrelevants, nfixedvars, nchgsides, cutoff) );
13987
13988 /* presolve constraint form the latest completion time point of view */
13989 SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
13990 irrelevants, nfixedvars, nchgsides, cutoff) );
13991
13992 return SCIP_OKAY;
13993}
13994
13995/** propagate the given cumulative condition */
13997 SCIP* scip, /**< SCIP data structure */
13998 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
13999 int nvars, /**< number of variables (jobs) */
14000 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14001 int* durations, /**< array containing corresponding durations */
14002 int* demands, /**< array containing corresponding demands */
14003 int capacity, /**< available cumulative capacity */
14004 int hmin, /**< left bound of time axis to be considered (including hmin) */
14005 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14006 SCIP_CONS* cons, /**< constraint which gets propagated */
14007 int* nchgbds, /**< pointer to store the number of variable bound changes */
14008 SCIP_Bool* initialized, /**< was conflict analysis initialized */
14009 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14010 SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14011 )
14012{
14013 SCIP_CONSHDLR* conshdlr;
14014 SCIP_CONSHDLRDATA* conshdlrdata;
14015 SCIP_Bool redundant;
14016
14017 assert(scip != NULL);
14018 assert(cons != NULL);
14019 assert(initialized != NULL);
14020 assert(*initialized == FALSE);
14021 assert(cutoff != NULL);
14022 assert(*cutoff == FALSE);
14023
14024 /* find the cumulative constraint handler */
14025 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14026 if( conshdlr == NULL )
14027 {
14028 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14029 return SCIP_PLUGINNOTFOUND;
14030 }
14031
14032 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14033 assert(conshdlrdata != NULL);
14034
14035 redundant = FALSE;
14036
14037 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14038 nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14039 nchgbds, &redundant, initialized, explanation, cutoff) );
14040
14041 return SCIP_OKAY;
14042}
14043
14044/** resolve propagation w.r.t. the cumulative condition */
14046 SCIP* scip, /**< SCIP data structure */
14047 int nvars, /**< number of start time variables (activities) */
14048 SCIP_VAR** vars, /**< array of start time variables */
14049 int* durations, /**< array of durations */
14050 int* demands, /**< array of demands */
14051 int capacity, /**< cumulative capacity */
14052 int hmin, /**< left bound of time axis to be considered (including hmin) */
14053 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14054 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14055 int inferinfo, /**< the user information */
14056 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14057 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14058 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14059 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14060 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14061 )
14062{
14063 SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14064 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14065
14066 return SCIP_OKAY;
14067}
14068
14069/** this method visualizes the cumulative structure in GML format */
14071 SCIP* scip, /**< SCIP data structure */
14072 SCIP_CONS* cons /**< cumulative constraint */
14073 )
14074{
14075 SCIP_CONSDATA* consdata;
14076 SCIP_HASHTABLE* vars;
14077 FILE* file;
14078 SCIP_VAR* var;
14079 char filename[SCIP_MAXSTRLEN];
14080 int nvars;
14081 int v;
14082
14083 SCIP_RETCODE retcode = SCIP_OKAY;
14084
14085 /* open file */
14086 (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14087 file = fopen(filename, "w");
14088
14089 /* check if the file was open */
14090 if( file == NULL )
14091 {
14092 SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14093 SCIPprintSysError(filename);
14094 return SCIP_FILECREATEERROR;
14095 }
14096
14097 consdata = SCIPconsGetData(cons);
14098 assert(consdata != NULL);
14099
14100 nvars = consdata->nvars;
14101
14102 SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14103 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14104
14105 /* create opening of the GML format */
14107
14108 for( v = 0; v < nvars; ++v )
14109 {
14110 char color[SCIP_MAXSTRLEN];
14111
14112 var = consdata->vars[v];
14113 assert(var != NULL);
14114
14115 SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14116
14117 if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14118 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14119 else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14120 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14121 else
14122 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14123
14124 SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14125 }
14126
14127 for( v = 0; v < nvars; ++v )
14128 {
14129 SCIP_VAR** vbdvars;
14130 int nvbdvars;
14131 int b;
14132
14133 var = consdata->vars[v];
14134 assert(var != NULL);
14135
14136 vbdvars = SCIPvarGetVlbVars(var);
14137 nvbdvars = SCIPvarGetNVlbs(var);
14138
14139 for( b = 0; b < nvbdvars; ++b )
14140 {
14141 if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14142 {
14143 SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14144 }
14145 }
14146
14147#ifdef SCIP_MORE_OUTPUT
14148 /* define to also output variable bounds */
14149 vbdvars = SCIPvarGetVubVars(var);
14150 nvbdvars = SCIPvarGetNVubs(var);
14151
14152 for( b = 0; b < nvbdvars; ++b )
14153 {
14154 if( SCIPhashtableExists(vars, vbdvars[b]) )
14155 {
14156 SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14157 }
14158 }
14159#endif
14160 }
14161
14162 /* create closing of the GML format */
14163 SCIPgmlWriteClosing(file);
14164TERMINATE:
14165 /* close file */
14166 fclose(file);
14167
14168 SCIPhashtableFree(&vars);
14169
14170 return retcode;
14171}
14172
14173/** sets method to solve an individual cumulative condition */
14175 SCIP* scip, /**< SCIP data structure */
14176 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14177 )
14178{
14179 SCIP_CONSHDLR* conshdlr;
14180 SCIP_CONSHDLRDATA* conshdlrdata;
14181
14182 /* find the cumulative constraint handler */
14183 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14184 if( conshdlr == NULL )
14185 {
14186 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14187 return SCIP_PLUGINNOTFOUND;
14188 }
14189
14190 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14191 assert(conshdlrdata != NULL);
14192
14193 conshdlrdata->solveCumulative = solveCumulative;
14194
14195 return SCIP_OKAY;
14196}
14197
14198/** solves given cumulative condition as independent sub problem
14199 *
14200 * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14201 * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14202 * solver was interrupted.
14203 */
14205 SCIP* scip, /**< SCIP data structure */
14206 int njobs, /**< number of jobs (activities) */
14207 SCIP_Real* ests, /**< array with the earlier start time for each job */
14208 SCIP_Real* lsts, /**< array with the latest start time for each job */
14209 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14210 int* durations, /**< array of durations */
14211 int* demands, /**< array of demands */
14212 int capacity, /**< cumulative capacity */
14213 int hmin, /**< left bound of time axis to be considered (including hmin) */
14214 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14215 SCIP_Real timelimit, /**< time limit for solving in seconds */
14216 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14217 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14218 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14219 SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14220 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14221 SCIP_Bool* error /**< pointer to store if an error occurred */
14222 )
14223{
14224 SCIP_CONSHDLR* conshdlr;
14225 SCIP_CONSHDLRDATA* conshdlrdata;
14226
14227 (*solved) = TRUE;
14228 (*infeasible) = FALSE;
14229 (*unbounded) = FALSE;
14230 (*error) = FALSE;
14231
14232 if( njobs == 0 )
14233 return SCIP_OKAY;
14234
14235 /* find the cumulative constraint handler */
14236 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14237 if( conshdlr == NULL )
14238 {
14239 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14240 (*error) = TRUE;
14241 return SCIP_PLUGINNOTFOUND;
14242 }
14243
14244 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14245 assert(conshdlrdata != NULL);
14246
14247 /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14248 if( timelimit > 0.0 && memorylimit > 10 )
14249 {
14250 SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14251 hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14252 }
14253
14254 return SCIP_OKAY;
14255}
14256
14257/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14258 * completion time
14259 */
14261 SCIP* scip, /**< SCIP data structure */
14262 SCIP_PROFILE* profile, /**< resource profile */
14263 int nvars, /**< number of variables (jobs) */
14264 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14265 int* durations, /**< array containing corresponding durations */
14266 int* demands /**< array containing corresponding demands */
14267 )
14268{
14269 SCIP_VAR* var;
14270 SCIP_HASHMAP* addedvars;
14271 int* copydemands;
14272 int* perm;
14273 int duration;
14274 int impliedest;
14275 int est;
14276 int impliedlct;
14277 int lct;
14278 int v;
14279
14280 /* create hash map for variables which are added, mapping to their duration */
14281 SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14282
14283 SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14284 SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14285
14286 /* sort variables w.r.t. job demands */
14287 for( v = 0; v < nvars; ++v )
14288 {
14289 copydemands[v] = demands[v];
14290 perm[v] = v;
14291 }
14292 SCIPsortDownIntInt(copydemands, perm, nvars);
14293
14294 /* add each job with its earliest start and latest completion time into the resource profile */
14295 for( v = 0; v < nvars; ++v )
14296 {
14297 int idx;
14298
14299 idx = perm[v];
14300 assert(idx >= 0 && idx < nvars);
14301
14302 var = vars[idx];
14303 assert(var != NULL);
14304
14305 duration = durations[idx];
14306 assert(duration > 0);
14307
14309 SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14310
14311 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14312 SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14313
14314 if( impliedest < impliedlct )
14315 {
14316 SCIP_Bool infeasible;
14317 int pos;
14318
14319 SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14320 assert(!infeasible);
14321 assert(pos == -1);
14322 }
14323
14324 if( est == impliedest && lct == impliedlct )
14325 {
14326 SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14327 }
14328 }
14329
14330 SCIPfreeBufferArray(scip, &copydemands);
14331 SCIPfreeBufferArray(scip, &perm);
14332
14333 SCIPhashmapFree(&addedvars);
14334
14335 return SCIP_OKAY;
14336}
14337
14338/** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14340 SCIP* scip, /**< SCIP data structure */
14341 SCIP_PROFILE* profile, /**< worst case resource profile */
14342 int capacity /**< capacity to check */
14343 )
14344{
14345 int* timepoints;
14346 int* loads;
14347 int ntimepoints;
14348 int t;
14349
14350 ntimepoints = SCIPprofileGetNTimepoints(profile);
14351 timepoints = SCIPprofileGetTimepoints(profile);
14352 loads = SCIPprofileGetLoads(profile);
14353
14354 /* find first time point which potentially violates the capacity restriction */
14355 for( t = 0; t < ntimepoints - 1; ++t )
14356 {
14357 /* check if the time point exceed w.r.t. worst case profile the capacity */
14358 if( loads[t] > capacity )
14359 {
14360 assert(t == 0 || loads[t-1] <= capacity);
14361 return timepoints[t];
14362 }
14363 }
14364
14365 return INT_MAX;
14366}
14367
14368/** 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}*/
14370 SCIP* scip, /**< SCIP data structure */
14371 SCIP_PROFILE* profile, /**< worst case profile */
14372 int capacity /**< capacity to check */
14373 )
14374{
14375 int* timepoints;
14376 int* loads;
14377 int ntimepoints;
14378 int t;
14379
14380 ntimepoints = SCIPprofileGetNTimepoints(profile);
14381 timepoints = SCIPprofileGetTimepoints(profile);
14382 loads = SCIPprofileGetLoads(profile);
14383
14384 /* find last time point which potentially violates the capacity restriction */
14385 for( t = ntimepoints - 1; t >= 0; --t )
14386 {
14387 /* check if at time point t the worst case resource profile exceeds the capacity */
14388 if( loads[t] > capacity )
14389 {
14390 assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14391 return timepoints[t+1];
14392 }
14393 }
14394
14395 return INT_MIN;
14396}
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:179
Proprule
Definition: cons_and.c:172
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 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)
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:266
#define SCIP_MAXSTRLEN
Definition: def.h:287
#define SCIP_Longint
Definition: def.h:157
#define SCIP_INVALID
Definition: def.h:192
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:242
#define SCIP_Real
Definition: def.h:172
#define SCIP_UNKNOWN
Definition: def.h:193
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:238
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:394
#define SCIP_LONGINT_FORMAT
Definition: def.h:164
#define MIN3(x, y, z)
Definition: def.h:250
#define SCIPABORT()
Definition: def.h:345
#define SCIP_LONGINT_MAX
Definition: def.h:158
#define SCIP_CALL(x)
Definition: def.h:373
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:415
#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:8950
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:8819
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:9062
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8961
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8744
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8859
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8789
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:8680
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8887
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:8922
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8869
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8936
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:8799
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8980
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8809
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:9085
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8849
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:9072
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:9408
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 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 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:9539
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 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:711
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:500
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:702
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:686
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:642
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:606
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:734
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:349
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:317
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:508
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:390
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1668
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip_prob.c:3185
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2843
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3043
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip_prob.c:180
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3111
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3284
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3264
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3077
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3426
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3195
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3442
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2349
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2662
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:2299
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2550
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3475
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:9124
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11215
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 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:10373
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10399
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:665
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1091
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:4227
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:4197
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:941
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:4217
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:8244
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8473
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8234
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8383
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2537
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip_cons.c:1626
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1297
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8413
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8343
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8523
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1272
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1322
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8403
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8275
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:998
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8433
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8453
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8214
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1813
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8463
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1525
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8493
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8393
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1139
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8483
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:104
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:324
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
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
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:97
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1422
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1701
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2167
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2010
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17523
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2165
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:125
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1213
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3491
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2502
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:17619
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5326
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18269
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4474
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18291
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17747
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1480
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17537
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3353
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18143
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17560
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:8524
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:5738
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17925
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5443
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:533
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17583
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1794
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18087
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17757
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4382
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:6784
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4560
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2128
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17767
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17418
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18301
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18311
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:17629
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18133
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18281
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:114
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18077
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8838
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8399
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:5624
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1992
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11941
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:194
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18343
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18323
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18333
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3295
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8752
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6830
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6876
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6820
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6772
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6862
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:6840
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6758
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6850
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:7053
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:7023
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6788
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:5541
void SCIPsortInt(int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10880
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:11038
void SCIPprintSysError(const char *message)
Definition: misc.c:10772
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#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
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:60
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:173
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:123
@ SCIP_BOUNDTYPE_UPPER
Definition: type_lp.h:57
@ SCIP_BOUNDTYPE_LOWER
Definition: type_lp.h:56
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
@ 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:61
@ SCIP_STATUS_TOTALNODELIMIT
Definition: type_stat.h:45
@ SCIP_STATUS_BESTSOLLIMIT
Definition: type_stat.h:57
@ SCIP_STATUS_SOLLIMIT
Definition: type_stat.h:56
@ SCIP_STATUS_UNBOUNDED
Definition: type_stat.h:63
@ SCIP_STATUS_UNKNOWN
Definition: type_stat.h:42
@ SCIP_STATUS_PRIMALLIMIT
Definition: type_stat.h:54
@ SCIP_STATUS_GAPLIMIT
Definition: type_stat.h:53
@ SCIP_STATUS_USERINTERRUPT
Definition: type_stat.h:43
@ SCIP_STATUS_TERMINATE
Definition: type_stat.h:65
@ SCIP_STATUS_INFORUNBD
Definition: type_stat.h:64
@ SCIP_STATUS_STALLNODELIMIT
Definition: type_stat.h:48
@ SCIP_STATUS_TIMELIMIT
Definition: type_stat.h:51
@ SCIP_STATUS_INFEASIBLE
Definition: type_stat.h:62
@ SCIP_STATUS_NODELIMIT
Definition: type_stat.h:44
@ SCIP_STATUS_DUALLIMIT
Definition: type_stat.h:55
@ SCIP_STATUS_MEMLIMIT
Definition: type_stat.h:52
@ SCIP_STATUS_RESTARTLIMIT
Definition: type_stat.h:60
#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:63
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:62
@ SCIP_VARSTATUS_FIXED
Definition: type_var.h:52
@ SCIP_VARSTATUS_MULTAGGR
Definition: type_var.h:54
@ SCIP_VARSTATUS_AGGREGATED
Definition: type_var.h:53
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:97