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#if 0
414 SCIP_VAR** vbdvars;
415 SCIP_VAR* vbdvar;
416 SCIP_Real* vbdcoefs;
417 SCIP_Real* vbdconsts;
418 void* image;
419 int nvbdvars;
420 int v;
421#endif
422
424
425#if 0
426 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
427
428 nvbdvars = SCIPvarGetNVlbs(var);
429 vbdvars = SCIPvarGetVlbVars(var);
430 vbdcoefs = SCIPvarGetVlbCoefs(var);
431 vbdconsts = SCIPvarGetVlbConstants(var);
432
433 for( v = 0; v < nvbdvars; ++v )
434 {
435 vbdvar = vbdvars[v];
436 assert(vbdvar != NULL);
437
438 image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
439
440 if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
441 {
442 int duration;
443 int vbdconst;
444
445 duration = (int)(size_t)image;
446 vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
447
448 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
450 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
451
452 if( duration >= vbdconst )
453 {
454 int impliedest;
455
456 impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
457
458 if( (*est) < impliedest )
459 {
460 (*est) = impliedest;
461
462 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
463 }
464 }
465 }
466 }
467#endif
468
469 return SCIP_OKAY;
470}
471
472/** returns the implied latest completion time */ /*lint -e{715}*/
473static
475 SCIP* scip, /**< SCIP data structure */
476 SCIP_VAR* var, /**< variable for which the implied est should be returned */
477 int duration, /**< duration of the given job */
478 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
479 int* lct /**< pointer to store the implied latest completion time */
480 )
481{ /*lint --e{715}*/
482#if 0
483 SCIP_VAR** vbdvars;
484 SCIP_VAR* vbdvar;
485 SCIP_Real* vbdcoefs;
486 SCIP_Real* vbdconsts;
487 int nvbdvars;
488 int v;
489#endif
490
491 (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
492
493#if 0
494 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
495
496 nvbdvars = SCIPvarGetNVubs(var);
497 vbdvars = SCIPvarGetVubVars(var);
498 vbdcoefs = SCIPvarGetVubCoefs(var);
499 vbdconsts = SCIPvarGetVubConstants(var);
500
501 for( v = 0; v < nvbdvars; ++v )
502 {
503 vbdvar = vbdvars[v];
504 assert(vbdvar != NULL);
505
506 if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
507 {
508 int vbdconst;
509
510 vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
511
512 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
514 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
515
516 if( duration >= -vbdconst )
517 {
518 int impliedlct;
519
520 impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
521
522 if( (*lct) > impliedlct )
523 {
524 (*lct) = impliedlct;
525
526 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
527 }
528 }
529 }
530 }
531#endif
532
533 return SCIP_OKAY;
534}
535
536/** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
537static
539 SCIP* scip, /**< SCIP data structure */
540 SCIP_CONSDATA* consdata, /**< constraint data */
541 SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
542 int** coefs, /**< pointer to store the coefficients */
543 int* nvars, /**< number if collect binary variables */
544 int* startindices, /**< permutation with rspect to the start times */
545 int curtime, /**< current point in time */
546 int nstarted, /**< number of jobs that start before the curtime or at curtime */
547 int nfinished /**< number of jobs that finished before curtime or at curtime */
548 )
549{
550 int nrowvars;
551 int startindex;
552 int size;
553
554 size = 10;
555 nrowvars = 0;
556 startindex = nstarted - 1;
557
558 SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
559 SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
560
561 /* search for the (nstarted - nfinished) jobs which are active at curtime */
562 while( nstarted - nfinished > nrowvars )
563 {
564 SCIP_VAR* var;
565 int endtime;
566 int duration;
567 int demand;
568 int varidx;
569
570 /* collect job information */
571 varidx = startindices[startindex];
572 assert(varidx >= 0 && varidx < consdata->nvars);
573
574 var = consdata->vars[varidx];
575 duration = consdata->durations[varidx];
576 demand = consdata->demands[varidx];
577 assert(var != NULL);
578
579 endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
580
581 /* check the end time of this job is larger than the curtime; in this case the job is still running */
582 if( endtime > curtime )
583 {
584 SCIP_VAR** binvars;
585 SCIP_Real* vals;
586 int nbinvars;
587 int start;
588 int end;
589 int b;
590
591 /* check if the linking constraints exists */
592 assert(SCIPexistsConsLinking(scip, var));
593 assert(SCIPgetConsLinking(scip, var) != NULL);
594 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
595
596 /* collect linking constraint information */
597 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
598 vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
599
600 start = curtime - duration + 1;
601 end = MIN(curtime, endtime - duration);
602
603 for( b = 0; b < nbinvars; ++b )
604 {
605 if( vals[b] < start )
606 continue;
607
608 if( vals[b] > end )
609 break;
610
611 assert(binvars[b] != NULL);
612
613 /* ensure array proper array size */
614 if( size == *nvars )
615 {
616 size *= 2;
617 SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
618 SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
619 }
620
621 (*vars)[*nvars] = binvars[b];
622 (*coefs)[*nvars] = demand;
623 (*nvars)++;
624 }
625 nrowvars++;
626 }
627
628 startindex--;
629 }
630
631 return SCIP_OKAY;
632}
633
634/** collect all integer variable which belong to jobs which can run at the point of interest */
635static
637 SCIP* scip, /**< SCIP data structure */
638 SCIP_CONSDATA* consdata, /**< constraint data */
639 SCIP_VAR*** activevars, /**< jobs that are currently running */
640 int* startindices, /**< permutation with rspect to the start times */
641 int curtime, /**< current point in time */
642 int nstarted, /**< number of jobs that start before the curtime or at curtime */
643 int nfinished, /**< number of jobs that finished before curtime or at curtime */
644 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
645 int* lhs /**< lhs for the new row sum of lbs + minoffset */
646 )
647{
648 SCIP_VAR* var;
649 int startindex;
650 int endtime;
651 int duration;
652 int starttime;
653
654 int varidx;
655 int sumofstarts;
656 int mindelta;
657 int counter;
658
659 assert(curtime >= consdata->hmin);
660 assert(curtime < consdata->hmax);
661
662 counter = 0;
663 sumofstarts = 0;
664
665 mindelta = INT_MAX;
666
667 startindex = nstarted - 1;
668
669 /* search for the (nstarted - nfinished) jobs which are active at curtime */
670 while( nstarted - nfinished > counter )
671 {
672 assert(startindex >= 0);
673
674 /* collect job information */
675 varidx = startindices[startindex];
676 assert(varidx >= 0 && varidx < consdata->nvars);
677
678 var = consdata->vars[varidx];
679 duration = consdata->durations[varidx];
680 assert(duration > 0);
681 assert(var != NULL);
682
683 if( lower )
685 else
687
688 endtime = MIN(starttime + duration, consdata->hmax);
689
690 /* check the end time of this job is larger than the curtime; in this case the job is still running */
691 if( endtime > curtime )
692 {
693 (*activevars)[counter] = var;
694 sumofstarts += starttime;
695 mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
696 counter++;
697 }
698
699 startindex--;
700 }
701
702 assert(mindelta > 0);
703 *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
704
705 return SCIP_OKAY;
706}
707
708/** initialize the sorted event point arrays */
709static
711 SCIP* scip, /**< SCIP data structure */
712 int nvars, /**< number of start time variables (activities) */
713 SCIP_VAR** vars, /**< array of start time variables */
714 int* durations, /**< array of durations per start time variable */
715 int* starttimes, /**< array to store sorted start events */
716 int* endtimes, /**< array to store sorted end events */
717 int* startindices, /**< permutation with rspect to the start times */
718 int* endindices, /**< permutation with rspect to the end times */
719 SCIP_Bool local /**< shall local bounds be used */
720 )
721{
722 SCIP_VAR* var;
723 int j;
724
725 assert(vars != NULL || nvars == 0);
726
727 /* assign variables, start and endpoints to arrays */
728 for ( j = 0; j < nvars; ++j )
729 {
730 assert(vars != NULL);
731
732 var = vars[j];
733 assert(var != NULL);
734
735 if( local )
736 starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
737 else
738 starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
739
740 startindices[j] = j;
741
742 if( local )
743 endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
744 else
745 endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
746
747 endindices[j] = j;
748 }
749
750 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
751 SCIPsortIntInt(starttimes, startindices, j);
752 SCIPsortIntInt(endtimes, endindices, j);
753}
754
755/** initialize the sorted event point arrays w.r.t. the given primal solutions */
756static
758 SCIP* scip, /**< SCIP data structure */
759 SCIP_SOL* sol, /**< solution */
760 int nvars, /**< number of start time variables (activities) */
761 SCIP_VAR** vars, /**< array of start time variables */
762 int* durations, /**< array of durations per start time variable */
763 int* starttimes, /**< array to store sorted start events */
764 int* endtimes, /**< array to store sorted end events */
765 int* startindices, /**< permutation with rspect to the start times */
766 int* endindices /**< permutation with rspect to the end times */
767 )
768{
769 SCIP_VAR* var;
770 int j;
771
772 assert(vars != NULL || nvars == 0);
773
774 /* assign variables, start and endpoints to arrays */
775 for ( j = 0; j < nvars; ++j )
776 {
777 assert(vars != NULL);
778
779 var = vars[j];
780 assert(var != NULL);
781
782 starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
783 startindices[j] = j;
784
785 endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
786 endindices[j] = j;
787 }
788
789 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
790 SCIPsortIntInt(starttimes, startindices, j);
791 SCIPsortIntInt(endtimes, endindices, j);
792}
793
794/** initialize the sorted event point arrays
795 *
796 * @todo Check the separation process!
797 */
798static
800 SCIP* scip, /**< SCIP data structure */
801 SCIP_CONSDATA* consdata, /**< constraint data */
802 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
803 int* starttimes, /**< array to store sorted start events */
804 int* endtimes, /**< array to store sorted end events */
805 int* startindices, /**< permutation with rspect to the start times */
806 int* endindices, /**< permutation with rspect to the end times */
807 int* nvars, /**< number of variables that are integral */
808 SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
809 )
810{
811 SCIP_VAR* var;
812 int tmpnvars;
813 int j;
814
815 tmpnvars = consdata->nvars;
816 *nvars = 0;
817
818 /* assign variables, start and endpoints to arrays */
819 for ( j = 0; j < tmpnvars; ++j )
820 {
821 var = consdata->vars[j];
822 assert(var != NULL);
823 assert(consdata->durations[j] > 0);
824 assert(consdata->demands[j] > 0);
825
826 if( lower )
827 {
828 /* only consider jobs that are at their lower or upper bound */
829 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
830 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
831 continue;
832
833 starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
834 startindices[*nvars] = j;
835
836 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
837 endindices[*nvars] = j;
838
839 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
840 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
841 consdata->durations[j],
842 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
843 consdata->demands[startindices[*nvars]]);
844
845 (*nvars)++;
846 }
847 else
848 {
849 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
850 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
851 continue;
852
853 starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
854 startindices[*nvars] = j;
855
856 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
857 endindices[*nvars] = j;
858
859 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
860 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
861 consdata->durations[j],
862 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
863 consdata->demands[startindices[*nvars]]);
864
865 (*nvars)++;
866 }
867 }
868
869 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
870 SCIPsortIntInt(starttimes, startindices, *nvars);
871 SCIPsortIntInt(endtimes, endindices, *nvars);
872
873#ifdef SCIP_DEBUG
874 SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
875
876 for ( j = 0; j < *nvars; ++j )
877 {
878 SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
879 startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
880 consdata->demands[startindices[j]]);
881 }
882
883 for ( j = 0; j < *nvars; ++j )
884 {
885 SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
886 consdata->demands[endindices[j]]);
887 }
888#endif
889}
890
891#ifdef SCIP_STATISTIC
892/** this method checks for relevant intervals for energetic reasoning */
893static
894SCIP_RETCODE computeRelevantEnergyIntervals(
895 SCIP* scip, /**< SCIP data structure */
896 int nvars, /**< number of start time variables (activities) */
897 SCIP_VAR** vars, /**< array of start time variables */
898 int* durations, /**< array of durations */
899 int* demands, /**< array of demands */
900 int capacity, /**< cumulative capacity */
901 int hmin, /**< left bound of time axis to be considered (including hmin) */
902 int hmax, /**< right bound of time axis to be considered (not including hmax) */
903 int** timepoints, /**< array to store relevant points in time */
904 SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
905 int* ntimepoints, /**< pointer to store the number of timepoints */
906 int* maxdemand, /**< pointer to store maximum over all demands */
907 SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
908 )
909{
910 int* starttimes; /* stores when each job is starting */
911 int* endtimes; /* stores when each job ends */
912 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
913 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
914
915 SCIP_Real totaldemand;
916 int curtime; /* point in time which we are just checking */
917 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
918
919 int j;
920
921 assert( scip != NULL );
922 assert(durations != NULL);
923 assert(demands != NULL);
924 assert(capacity >= 0);
925
926 /* if no activities are associated with this cumulative then this constraint is redundant */
927 if( nvars == 0 )
928 return SCIP_OKAY;
929
930 assert(vars != NULL);
931
932 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
933 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
934 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
935 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
936
937 /* create event point arrays */
938 createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
939
940 endindex = 0;
941 totaldemand = 0.0;
942
943 *ntimepoints = 0;
944 (*timepoints)[0] = starttimes[0];
945 (*cumulativedemands)[0] = 0;
946 *maxdemand = 0;
947
948 /* check each startpoint of a job whether the capacity is kept or not */
949 for( j = 0; j < nvars; ++j )
950 {
951 int lct;
952 int idx;
953
954 curtime = starttimes[j];
955
956 if( curtime >= hmax )
957 break;
958
959 /* free all capacity usages of jobs the are no longer running */
960 while( endindex < nvars && endtimes[endindex] <= curtime )
961 {
962 int est;
963
964 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
965 {
966 (*ntimepoints)++;
967 (*timepoints)[*ntimepoints] = endtimes[endindex];
968 (*cumulativedemands)[*ntimepoints] = 0;
969 }
970
971 idx = endindices[endindex];
973 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
974 endindex++;
975
976 (*cumulativedemands)[*ntimepoints] = totaldemand;
977 }
978
979 idx = startindices[j];
980 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
981 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
982
983 if( (*timepoints)[*ntimepoints] < curtime )
984 {
985 (*ntimepoints)++;
986 (*timepoints)[*ntimepoints] = curtime;
987 (*cumulativedemands)[*ntimepoints] = 0;
988 }
989
990 (*cumulativedemands)[*ntimepoints] = totaldemand;
991
992 /* add the relative capacity requirements for all job which start at the curtime */
993 while( j+1 < nvars && starttimes[j+1] == curtime )
994 {
995 ++j;
996 idx = startindices[j];
997 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
998 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
999
1000 (*cumulativedemands)[*ntimepoints] = totaldemand;
1001 }
1002 } /*lint --e{850}*/
1003
1004 /* free all capacity usages of jobs that are no longer running */
1005 while( endindex < nvars/* && endtimes[endindex] < hmax*/)
1006 {
1007 int est;
1008 int idx;
1009
1010 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
1011 {
1012 (*ntimepoints)++;
1013 (*timepoints)[*ntimepoints] = endtimes[endindex];
1014 (*cumulativedemands)[*ntimepoints] = 0;
1015 }
1016
1017 idx = endindices[endindex];
1018 est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
1019 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
1020 (*cumulativedemands)[*ntimepoints] = totaldemand;
1021
1022 ++endindex;
1023 }
1024
1025 (*ntimepoints)++;
1026 /* compute minimum free capacity */
1027 (*minfreecapacity) = INT_MAX;
1028 for( j = 0; j < *ntimepoints; ++j )
1029 {
1030 if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1031 *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1032 }
1033
1034 /* free buffer arrays */
1035 SCIPfreeBufferArray(scip, &endindices);
1036 SCIPfreeBufferArray(scip, &startindices);
1037 SCIPfreeBufferArray(scip, &endtimes);
1038 SCIPfreeBufferArray(scip, &starttimes);
1039
1040 return SCIP_OKAY;
1041}
1042
1043/** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1044static
1045SCIP_RETCODE evaluateCumulativeness(
1046 SCIP* scip, /**< pointer to scip */
1047 SCIP_CONS* cons /**< cumulative constraint */
1048 )
1049{
1050 SCIP_CONSDATA* consdata;
1051 int nvars;
1052 int v;
1053 int capacity;
1054
1055 /* output values: */
1056 SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1057 SCIP_Real cumfactor1;
1058 SCIP_Real resstrength1; /* overall strength */
1059 SCIP_Real resstrength2; /* timepoint wise maximum */
1060
1061 /* helpful variables: */
1062 SCIP_Real globalpeak;
1063 SCIP_Real globalmaxdemand;
1064
1065 /* get constraint data structure */
1066 consdata = SCIPconsGetData(cons);
1067 assert(consdata != NULL);
1068
1069 nvars = consdata->nvars;
1070 capacity = consdata->capacity;
1071 globalpeak = 0.0;
1072 globalmaxdemand = 0.0;
1073
1074 disjfactor2 = 0.0;
1075 cumfactor1 = 0.0;
1076 resstrength2 = 0.0;
1077
1078 /* check each starting time (==each job, but inefficient) */
1079 for( v = 0; v < nvars; ++v )
1080 {
1081 SCIP_Real peak;
1082 SCIP_Real maxdemand;
1083 SCIP_Real deltademand;
1084 int ndemands;
1085 int nlarge;
1086
1087 int timepoint;
1088 int j;
1089 timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1090 peak = consdata->demands[v];
1091 ndemands = 1;
1092 maxdemand = 0;
1093 nlarge = 0;
1094
1095 if( consdata->demands[v] > capacity / 3 )
1096 nlarge++;
1097
1098 for( j = 0; j < nvars; ++j )
1099 {
1100 int lb;
1101
1102 if( j == v )
1103 continue;
1104
1105 maxdemand = 0.0;
1106 lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1107
1108 if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1109 {
1110 peak += consdata->demands[j];
1111 ndemands++;
1112
1113 if( consdata->demands[j] > consdata->capacity / 3 )
1114 nlarge++;
1115 }
1116 }
1117
1118 deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1119 globalpeak = MAX(globalpeak, peak);
1120 globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1121
1122 if( peak > capacity )
1123 {
1124 disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1125 cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1126 resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1127 }
1128 }
1129
1130 resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1131
1132 consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1133 consdata->disjfactor2 = disjfactor2;
1134 consdata->cumfactor1 = cumfactor1;
1135 consdata->resstrength2 = resstrength2;
1136 consdata->resstrength1 = resstrength1;
1137
1138 /* get estimated res strength */
1139 {
1140 int* timepoints;
1141 SCIP_Real* estimateddemands;
1142 int ntimepoints;
1143 int maxdemand;
1144 SCIP_Real minfreecapacity;
1145
1146 SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1147 SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1148
1149 ntimepoints = 0;
1150 minfreecapacity = INT_MAX;
1151
1152 SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1153 consdata->durations, consdata->demands,
1154 capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1155 &ntimepoints, &maxdemand, &minfreecapacity) );
1156
1157 /* free buffer arrays */
1158 SCIPfreeBufferArray(scip, &estimateddemands);
1159 SCIPfreeBufferArray(scip, &timepoints);
1160
1161 consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1162 }
1163
1164 SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1165 SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1166 consdata->estimatedstrength);
1167
1168 return SCIP_OKAY;
1169}
1170#endif
1171
1172/** gets the active variables together with the constant */
1173static
1175 SCIP* scip, /**< SCIP data structure */
1176 SCIP_VAR** var, /**< pointer to store the active variable */
1177 int* scalar, /**< pointer to store the scalar */
1178 int* constant /**< pointer to store the constant */
1179 )
1180{
1181 if( !SCIPvarIsActive(*var) )
1182 {
1183 SCIP_Real realscalar;
1184 SCIP_Real realconstant;
1185
1186 realscalar = 1.0;
1187 realconstant = 0.0;
1188
1190
1191 /* transform variable to active variable */
1192 SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1193 assert(!SCIPisZero(scip, realscalar));
1194 assert(SCIPvarIsActive(*var));
1195
1196 if( realconstant < 0.0 )
1197 (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1198 else
1199 (*constant) = SCIPconvertRealToInt(scip, realconstant);
1200
1201 if( realscalar < 0.0 )
1202 (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1203 else
1204 (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1205 }
1206 else
1207 {
1208 (*scalar) = 1;
1209 (*constant) = 0;
1210 }
1211
1212 assert(*scalar != 0);
1213
1214 return SCIP_OKAY;
1215}
1216
1217/** computes the total energy of all jobs */
1218static
1220 int* durations, /**< array of job durations */
1221 int* demands, /**< array of job demands */
1222 int njobs /**< number of jobs */
1223 )
1224{
1225 SCIP_Longint energy;
1226 int j;
1227
1228 energy = 0;
1229
1230 for( j = 0; j < njobs; ++j )
1231 energy += (SCIP_Longint) durations[j] * demands[j];
1232
1233 return energy;
1234}
1235
1236/**@} */
1237
1238/**@name Default method to solve a cumulative condition
1239 *
1240 * @{
1241 */
1242
1243/** setup and solve subscip to solve single cumulative condition */
1244static
1246 SCIP* subscip, /**< subscip data structure */
1247 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1248 int* durations, /**< array of durations */
1249 int* demands, /**< array of demands */
1250 int njobs, /**< number of jobs (activities) */
1251 int capacity, /**< cumulative capacity */
1252 int hmin, /**< left bound of time axis to be considered (including hmin) */
1253 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1254 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1255 SCIP_Real timelimit, /**< time limit for solving in seconds */
1256 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1257 SCIP_Real* ests, /**< array of earliest start times for each job */
1258 SCIP_Real* lsts, /**< array of latest start times for each job */
1259 SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1260 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1261 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1262 SCIP_Bool* error /**< pointer to store if an error occurred */
1263 )
1264{
1265 SCIP_VAR** subvars;
1266 SCIP_CONS* cons;
1267
1268 char name[SCIP_MAXSTRLEN];
1269 int v;
1270 SCIP_RETCODE retcode;
1271
1272 assert(subscip != NULL);
1273
1274 /* copy all plugins */
1276
1277 /* create the subproblem */
1278 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1279
1280 SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1281
1282 /* create for each job a start time variable */
1283 for( v = 0; v < njobs; ++v )
1284 {
1285 SCIP_Real objval;
1286
1287 /* construct variable name */
1288 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1289
1290 if( objvals == NULL )
1291 objval = 0.0;
1292 else
1293 objval = objvals[v];
1294
1295 SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1296 SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1297 }
1298
1299 /* create cumulative constraint */
1300 SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1301 njobs, subvars, durations, demands, capacity) );
1302
1303 /* set effective horizon */
1304 SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1305 SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1306
1307 /* add cumulative constraint */
1308 SCIP_CALL( SCIPaddCons(subscip, cons) );
1309 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1310
1311 /* set CP solver settings
1312 *
1313 * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1314 * time limit.
1315 */
1317
1318 /* do not abort subproblem on CTRL-C */
1319 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1320
1321 /* disable output to console */
1322 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1323
1324 /* set limits for the subproblem */
1325 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1326 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1327 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1328
1329 /* forbid recursive call of heuristics and separators solving subMIPs */
1330 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1331
1332 /* solve single cumulative constraint by branch and bound */
1333 retcode = SCIPsolve(subscip);
1334
1335 if( retcode != SCIP_OKAY )
1336 (*error) = TRUE;
1337 else
1338 {
1339 SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1340
1341 /* evaluated solution status */
1342 switch( SCIPgetStatus(subscip) )
1343 {
1346 (*infeasible) = TRUE;
1347 (*solved) = TRUE;
1348 break;
1350 (*unbounded) = TRUE;
1351 (*solved) = TRUE;
1352 break;
1354 {
1355 SCIP_SOL* sol;
1356 SCIP_Real solval;
1357
1358 sol = SCIPgetBestSol(subscip);
1359 assert(sol != NULL);
1360
1361 for( v = 0; v < njobs; ++v )
1362 {
1363 solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1364
1365 ests[v] = solval;
1366 lsts[v] = solval;
1367 }
1368 (*solved) = TRUE;
1369 break;
1370 }
1377 /* transfer the global bound changes */
1378 for( v = 0; v < njobs; ++v )
1379 {
1380 ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1381 lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1382 }
1383 (*solved) = FALSE;
1384 break;
1385
1394 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1395 return SCIP_INVALIDDATA;
1396 }
1397 }
1398
1399 /* release all variables */
1400 for( v = 0; v < njobs; ++v )
1401 {
1402 SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1403 }
1404
1405 SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1406
1407 return SCIP_OKAY;
1408}
1409
1410/** solve single cumulative condition using SCIP and a single cumulative constraint */
1411static
1412SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1413{
1414 SCIP* subscip;
1415
1416 SCIP_RETCODE retcode;
1417
1418 assert(njobs > 0);
1419
1420 (*solved) = FALSE;
1421 (*infeasible) = FALSE;
1422 (*unbounded) = FALSE;
1423 (*error) = FALSE;
1424
1425 SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1426
1427 /* initialize the sub-problem */
1428 SCIP_CALL( SCIPcreate(&subscip) );
1429
1430 /* create and solve the subproblem. catch possible errors */
1431 retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1432 njobs, capacity, hmin, hmax,
1433 maxnodes, timelimit, memorylimit,
1434 ests, lsts,
1435 infeasible, unbounded, solved, error);
1436
1437 /* free the subscip in any case */
1438 SCIP_CALL( SCIPfree(&subscip) );
1439
1440 SCIP_CALL( retcode );
1441
1442 return SCIP_OKAY;
1443}
1444
1445#if 0
1446/** solve single cumulative condition using SCIP and the time indexed formulation */
1447static
1448SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1449{
1450 SCIP* subscip;
1451 SCIP_VAR*** binvars;
1452 SCIP_RETCODE retcode;
1453 char name[SCIP_MAXSTRLEN];
1454 int minest;
1455 int maxlct;
1456 int t;
1457 int v;
1458
1459 assert(njobs > 0);
1460
1461 (*solved) = FALSE;
1462 (*infeasible) = FALSE;
1463 (*unbounded) = FALSE;
1464 (*error) = FALSE;
1465
1466 SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1467
1468 /* initialize the sub-problem */
1469 SCIP_CALL( SCIPcreate(&subscip) );
1470
1471 /* copy all plugins */
1473
1474 /* create the subproblem */
1475 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1476
1477 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1478
1479 minest = INT_MAX;
1480 maxlct = INT_MIN;
1481
1482 /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1483 * partitioning constrain which forces that job starts
1484 */
1485 for( v = 0; v < njobs; ++v )
1486 {
1487 SCIP_CONS* cons;
1488 SCIP_Real objval;
1489 int timeinterval;
1490 int est;
1491 int lst;
1492
1493 if( objvals == NULL )
1494 objval = 0.0;
1495 else
1496 objval = objvals[v];
1497
1498 est = ests[v];
1499 lst = lsts[v];
1500
1501 /* compute number of possible start points */
1502 timeinterval = lst - est + 1;
1503 assert(timeinterval > 0);
1504
1505 /* compute the smallest earliest start time and largest latest completion time */
1506 minest = MIN(minest, est);
1507 maxlct = MAX(maxlct, lst + durations[v]);
1508
1509 /* construct constraint name */
1510 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1511
1512 SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1513
1514 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1515
1516 for( t = 0; t < timeinterval; ++t )
1517 {
1518 SCIP_VAR* binvar;
1519
1520 /* construct varibale name */
1521 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1522
1523 SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1524 SCIP_CALL( SCIPaddVar(subscip, binvar) );
1525
1526 /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1527 SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1528
1529 binvars[v][t] = binvar;
1530 }
1531
1532 /* add and release the set partitioning constraint */
1533 SCIP_CALL( SCIPaddCons(subscip, cons) );
1534 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1535 }
1536
1537 /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1538 hmin = MAX(hmin, minest);
1539 hmax = MIN(hmax, maxlct);
1540 assert(hmin > INT_MIN);
1541 assert(hmax < INT_MAX);
1542 assert(hmin < hmax);
1543
1544 /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1545 for( t = hmin; t < hmax; ++t )
1546 {
1547 SCIP_CONS* cons;
1548
1549 /* construct constraint name */
1550 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1551
1552 /* create an empty knapsack constraint */
1553 SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1554
1555 /* add all jobs which potentially can be processed at that time point */
1556 for( v = 0; v < njobs; ++v )
1557 {
1558 int duration;
1559 int demand;
1560 int start;
1561 int end;
1562 int est;
1563 int lst;
1564 int k;
1565
1566 est = ests[v];
1567 lst = lsts[v] ;
1568
1569 duration = durations[v];
1570 assert(duration > 0);
1571
1572 /* check if the varibale is processed potentially at time point t */
1573 if( t < est || t >= lst + duration )
1574 continue;
1575
1576 demand = demands[v];
1577 assert(demand >= 0);
1578
1579 start = MAX(t - duration + 1, est);
1580 end = MIN(t, lst);
1581
1582 assert(start <= end);
1583
1584 for( k = start; k <= end; ++k )
1585 {
1586 assert(binvars[v][k] != NULL);
1587 SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1588 }
1589 }
1590
1591 /* add and release the knapsack constraint */
1592 SCIP_CALL( SCIPaddCons(subscip, cons) );
1593 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1594 }
1595
1596 /* do not abort subproblem on CTRL-C */
1597 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1598
1599 /* disable output to console */
1600 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1601
1602 /* set limits for the subproblem */
1603 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1604 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1605 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1606
1607 /* solve single cumulative constraint by branch and bound */
1608 retcode = SCIPsolve(subscip);
1609
1610 if( retcode != SCIP_OKAY )
1611 (*error) = TRUE;
1612 else
1613 {
1614 SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1615
1616 /* evaluated solution status */
1617 switch( SCIPgetStatus(subscip) )
1618 {
1621 (*infeasible) = TRUE;
1622 (*solved) = TRUE;
1623 break;
1625 (*unbounded) = TRUE;
1626 (*solved) = TRUE;
1627 break;
1629 {
1630 SCIP_SOL* sol;
1631
1632 sol = SCIPgetBestSol(subscip);
1633 assert(sol != NULL);
1634
1635 for( v = 0; v < njobs; ++v )
1636 {
1637 int timeinterval;
1638 int est;
1639 int lst;
1640
1641 est = ests[v];
1642 lst = lsts[v];
1643
1644 /* compute number of possible start points */
1645 timeinterval = lst - est + 1;
1646
1647 /* check which binary varibale is set to one */
1648 for( t = 0; t < timeinterval; ++t )
1649 {
1650 if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1651 {
1652 ests[v] = est + t;
1653 lsts[v] = est + t;
1654 break;
1655 }
1656 }
1657 }
1658
1659 (*solved) = TRUE;
1660 break;
1661 }
1667 /* transfer the global bound changes */
1668 for( v = 0; v < njobs; ++v )
1669 {
1670 int timeinterval;
1671 int est;
1672 int lst;
1673
1674 est = ests[v];
1675 lst = lsts[v];
1676
1677 /* compute number of possible start points */
1678 timeinterval = lst - est + 1;
1679
1680 /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1681 for( t = 0; t < timeinterval; ++t )
1682 {
1683 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1684 {
1685 ests[v] = est + t;
1686 break;
1687 }
1688 }
1689
1690 /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1691 for( t = timeinterval - 1; t >= 0; --t )
1692 {
1693 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1694 {
1695 lsts[v] = est + t;
1696 break;
1697 }
1698 }
1699 }
1700 (*solved) = FALSE;
1701 break;
1702
1708 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1709 return SCIP_INVALIDDATA;
1710 }
1711 }
1712
1713 /* release all variables */
1714 for( v = 0; v < njobs; ++v )
1715 {
1716 int timeinterval;
1717 int est;
1718 int lst;
1719
1720 est = ests[v];
1721 lst = lsts[v];
1722
1723 /* compute number of possible start points */
1724 timeinterval = lst - est + 1;
1725
1726 for( t = 0; t < timeinterval; ++t )
1727 {
1728 SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1729 }
1730 SCIPfreeBufferArray(subscip, &binvars[v]);
1731 }
1732
1733 SCIPfreeBufferArray(subscip, &binvars);
1734
1735 SCIP_CALL( SCIPfree(&subscip) );
1736
1737 return SCIP_OKAY;
1738}
1739#endif
1740
1741/**@} */
1742
1743/**@name Constraint handler data
1744 *
1745 * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1746 * handler.
1747 *
1748 * @{
1749 */
1750
1751/** creates constaint handler data for cumulative constraint handler */
1752static
1754 SCIP* scip, /**< SCIP data structure */
1755 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1756 SCIP_EVENTHDLR* eventhdlr /**< event handler */
1757 )
1758{
1759 /* create precedence constraint handler data */
1760 assert(scip != NULL);
1761 assert(conshdlrdata != NULL);
1762 assert(eventhdlr != NULL);
1763
1764 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1765
1766 /* set event handler for checking if bounds of start time variables are tighten */
1767 (*conshdlrdata)->eventhdlr = eventhdlr;
1768
1769 /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1770 (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1771
1772#ifdef SCIP_STATISTIC
1773 (*conshdlrdata)->nlbtimetable = 0;
1774 (*conshdlrdata)->nubtimetable = 0;
1775 (*conshdlrdata)->ncutofftimetable = 0;
1776 (*conshdlrdata)->nlbedgefinder = 0;
1777 (*conshdlrdata)->nubedgefinder = 0;
1778 (*conshdlrdata)->ncutoffedgefinder = 0;
1779 (*conshdlrdata)->ncutoffoverload = 0;
1780 (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1781
1782 (*conshdlrdata)->nirrelevantjobs = 0;
1783 (*conshdlrdata)->nalwaysruns = 0;
1784 (*conshdlrdata)->nremovedlocks = 0;
1785 (*conshdlrdata)->ndualfixs = 0;
1786 (*conshdlrdata)->ndecomps = 0;
1787 (*conshdlrdata)->ndualbranchs = 0;
1788 (*conshdlrdata)->nallconsdualfixs = 0;
1789 (*conshdlrdata)->naddedvarbounds = 0;
1790 (*conshdlrdata)->naddeddisjunctives = 0;
1791#endif
1792
1793 return SCIP_OKAY;
1794}
1795
1796/** frees constraint handler data for logic or constraint handler */
1797static
1799 SCIP* scip, /**< SCIP data structure */
1800 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1801 )
1802{
1803 assert(conshdlrdata != NULL);
1804 assert(*conshdlrdata != NULL);
1805
1806 SCIPfreeBlockMemory(scip, conshdlrdata);
1807}
1808
1809/**@} */
1810
1811
1812/**@name Constraint data methods
1813 *
1814 * @{
1815 */
1816
1817/** catches bound change events for all variables in transformed cumulative constraint */
1818static
1820 SCIP* scip, /**< SCIP data structure */
1821 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1822 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1823 )
1824{
1825 int v;
1826
1827 assert(scip != NULL);
1828 assert(consdata != NULL);
1829 assert(eventhdlr != NULL);
1830
1831 /* catch event for every single variable */
1832 for( v = 0; v < consdata->nvars; ++v )
1833 {
1834 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1835 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1836 }
1837
1838 return SCIP_OKAY;
1839}
1840
1841/** drops events for variable at given position */
1842static
1844 SCIP* scip, /**< SCIP data structure */
1845 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1846 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1847 int pos /**< array position of variable to catch bound change events for */
1848 )
1849{
1850 assert(scip != NULL);
1851 assert(consdata != NULL);
1852 assert(eventhdlr != NULL);
1853 assert(0 <= pos && pos < consdata->nvars);
1854 assert(consdata->vars[pos] != NULL);
1855
1856 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1857 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1858
1859 return SCIP_OKAY;
1860}
1861
1862/** drops bound change events for all variables in transformed linear constraint */
1863static
1865 SCIP* scip, /**< SCIP data structure */
1866 SCIP_CONSDATA* consdata, /**< linear constraint data */
1867 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1868 )
1869{
1870 int v;
1871
1872 assert(scip != NULL);
1873 assert(consdata != NULL);
1874
1875 /* drop event of every single variable */
1876 for( v = 0; v < consdata->nvars; ++v )
1877 {
1878 SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1879 }
1880
1881 return SCIP_OKAY;
1882}
1883
1884/** initialize variable lock data structure */
1885static
1887 SCIP_CONSDATA* consdata, /**< constraint data */
1888 SCIP_Bool locked /**< should the variable be locked? */
1889 )
1890{
1891 int nvars;
1892 int v;
1893
1894 nvars = consdata->nvars;
1895
1896 /* initialize locking arrays */
1897 for( v = 0; v < nvars; ++v )
1898 {
1899 consdata->downlocks[v] = locked;
1900 consdata->uplocks[v] = locked;
1901 }
1902}
1903
1904/** creates constraint data of cumulative constraint */
1905static
1907 SCIP* scip, /**< SCIP data structure */
1908 SCIP_CONSDATA** consdata, /**< pointer to consdata */
1909 SCIP_VAR** vars, /**< array of integer variables */
1910 SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1911 int* durations, /**< array containing corresponding durations */
1912 int* demands, /**< array containing corresponding demands */
1913 int nvars, /**< number of variables */
1914 int capacity, /**< available cumulative capacity */
1915 int hmin, /**< left bound of time axis to be considered (including hmin) */
1916 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1917 SCIP_Bool check /**< is the corresponding constraint a check constraint */
1918 )
1919{
1920 int v;
1921
1922 assert(scip != NULL);
1923 assert(consdata != NULL);
1924 assert(vars != NULL || nvars > 0);
1925 assert(demands != NULL);
1926 assert(durations != NULL);
1927 assert(capacity >= 0);
1928 assert(hmin >= 0);
1929 assert(hmin < hmax);
1930
1931 /* create constraint data */
1932 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1933
1934 (*consdata)->hmin = hmin;
1935 (*consdata)->hmax = hmax;
1936
1937 (*consdata)->capacity = capacity;
1938 (*consdata)->demandrows = NULL;
1939 (*consdata)->demandrowssize = 0;
1940 (*consdata)->ndemandrows = 0;
1941 (*consdata)->scoverrows = NULL;
1942 (*consdata)->nscoverrows = 0;
1943 (*consdata)->scoverrowssize = 0;
1944 (*consdata)->bcoverrows = NULL;
1945 (*consdata)->nbcoverrows = 0;
1946 (*consdata)->bcoverrowssize = 0;
1947 (*consdata)->nvars = nvars;
1948 (*consdata)->varssize = nvars;
1949 (*consdata)->signature = 0;
1950 (*consdata)->validsignature = FALSE;
1951 (*consdata)->normalized = FALSE;
1952 (*consdata)->covercuts = FALSE;
1953 (*consdata)->propagated = FALSE;
1954 (*consdata)->varbounds = FALSE;
1955 (*consdata)->triedsolving = FALSE;
1956
1957 if( nvars > 0 )
1958 {
1959 assert(vars != NULL); /* for flexelint */
1960
1961 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1962 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1963 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1964 (*consdata)->linkingconss = NULL;
1965
1966 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1967 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1968
1969 /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
1970 initializeLocks(*consdata, check);
1971
1972 if( linkingconss != NULL )
1973 {
1974 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1975 }
1976
1977 /* transform variables, if they are not yet transformed */
1978 if( SCIPisTransformed(scip) )
1979 {
1980 SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1981
1982 /* get transformed variables and do NOT captures these */
1983 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1984
1985 /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1986 * been multi-aggregated
1987 */
1988 for( v = 0; v < nvars; ++v )
1989 {
1990 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1991 }
1992
1993 if( linkingconss != NULL )
1994 {
1995 /* get transformed constraints and captures these */
1996 SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1997
1998 for( v = 0; v < nvars; ++v )
1999 assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
2000 }
2001 }
2002
2003#ifndef NDEBUG
2004 /* only binary and integer variables can be used in cumulative constraints
2005 * for fractional variable values, the constraint cannot be checked
2006 */
2007 for( v = 0; v < (*consdata)->nvars; ++v )
2008 assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
2009#endif
2010 }
2011 else
2012 {
2013 (*consdata)->vars = NULL;
2014 (*consdata)->downlocks = NULL;
2015 (*consdata)->uplocks = NULL;
2016 (*consdata)->demands = NULL;
2017 (*consdata)->durations = NULL;
2018 (*consdata)->linkingconss = NULL;
2019 }
2020
2021 /* initialize values for running propagation algorithms efficiently */
2022 (*consdata)->resstrength1 = -1.0;
2023 (*consdata)->resstrength2 = -1.0;
2024 (*consdata)->cumfactor1 = -1.0;
2025 (*consdata)->disjfactor1 = -1.0;
2026 (*consdata)->disjfactor2 = -1.0;
2027 (*consdata)->estimatedstrength = -1.0;
2028
2029 SCIPstatistic( (*consdata)->maxpeak = -1 );
2030
2031 return SCIP_OKAY;
2032}
2033
2034/** releases LP rows of constraint data and frees rows array */
2035static
2037 SCIP* scip, /**< SCIP data structure */
2038 SCIP_CONSDATA** consdata /**< constraint data */
2039 )
2040{
2041 int r;
2042
2043 assert(consdata != NULL);
2044 assert(*consdata != NULL);
2045
2046 for( r = 0; r < (*consdata)->ndemandrows; ++r )
2047 {
2048 assert((*consdata)->demandrows[r] != NULL);
2049 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2050 }
2051
2052 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2053
2054 (*consdata)->ndemandrows = 0;
2055 (*consdata)->demandrowssize = 0;
2056
2057 /* free rows of cover cuts */
2058 for( r = 0; r < (*consdata)->nscoverrows; ++r )
2059 {
2060 assert((*consdata)->scoverrows[r] != NULL);
2061 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2062 }
2063
2064 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2065
2066 (*consdata)->nscoverrows = 0;
2067 (*consdata)->scoverrowssize = 0;
2068
2069 for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2070 {
2071 assert((*consdata)->bcoverrows[r] != NULL);
2072 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2073 }
2074
2075 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2076
2077 (*consdata)->nbcoverrows = 0;
2078 (*consdata)->bcoverrowssize = 0;
2079
2080 (*consdata)->covercuts = FALSE;
2081
2082 return SCIP_OKAY;
2083}
2084
2085/** frees a cumulative constraint data */
2086static
2088 SCIP* scip, /**< SCIP data structure */
2089 SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2090 )
2091{
2092 int varssize;
2093 int nvars;
2094
2095 assert(consdata != NULL);
2096 assert(*consdata != NULL);
2097
2098 nvars = (*consdata)->nvars;
2099 varssize = (*consdata)->varssize;
2100
2101 if( varssize > 0 )
2102 {
2103 int v;
2104
2105 /* release and free the rows */
2106 SCIP_CALL( consdataFreeRows(scip, consdata) );
2107
2108 /* release the linking constraints if they were generated */
2109 if( (*consdata)->linkingconss != NULL )
2110 {
2111 for( v = nvars-1; v >= 0; --v )
2112 {
2113 assert((*consdata)->linkingconss[v] != NULL );
2114 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2115 }
2116
2117 SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2118 }
2119
2120 /* free arrays */
2121 SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2122 SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2123 SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2124 SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2125 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2126 }
2127
2128 /* free memory */
2129 SCIPfreeBlockMemory(scip, consdata);
2130
2131 return SCIP_OKAY;
2132}
2133
2134/** prints cumulative constraint to file stream */
2135static
2137 SCIP* scip, /**< SCIP data structure */
2138 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2139 FILE* file /**< output file (or NULL for standard output) */
2140 )
2141{
2142 int v;
2143
2144 assert(consdata != NULL);
2145
2146 /* print coefficients */
2147 SCIPinfoMessage( scip, file, "cumulative(");
2148
2149 for( v = 0; v < consdata->nvars; ++v )
2150 {
2151 assert(consdata->vars[v] != NULL);
2152 if( v > 0 )
2153 SCIPinfoMessage(scip, file, ", ");
2154 SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2155 SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2156 consdata->durations[v], consdata->demands[v]);
2157 }
2158 SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2159}
2160
2161/** deletes coefficient at given position from constraint data */
2162static
2164 SCIP* scip, /**< SCIP data structure */
2165 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2166 SCIP_CONS* cons, /**< knapsack constraint */
2167 int pos /**< position of coefficient to delete */
2168 )
2169{
2170 SCIP_CONSHDLR* conshdlr;
2171 SCIP_CONSHDLRDATA* conshdlrdata;
2172
2173 assert(scip != NULL);
2174 assert(consdata != NULL);
2175 assert(cons != NULL);
2176 assert(SCIPconsIsTransformed(cons));
2177 assert(!SCIPinProbing(scip));
2178
2179 SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2180 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2181
2182 /* remove the rounding locks for the deleted variable */
2183 SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2184
2185 consdata->downlocks[pos] = FALSE;
2186 consdata->uplocks[pos] = FALSE;
2187
2188 if( consdata->linkingconss != NULL )
2189 {
2190 SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2191 }
2192
2193 /* get event handler */
2194 conshdlr = SCIPconsGetHdlr(cons);
2195 assert(conshdlr != NULL);
2196 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2197 assert(conshdlrdata != NULL);
2198 assert(conshdlrdata->eventhdlr != NULL);
2199
2200 /* drop events */
2201 SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2202
2203 SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2204 SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2205
2206 /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2207 * position
2208 */
2209 if( pos != consdata->nvars - 1 )
2210 {
2211 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2212 consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2213 consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2214 consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2215 consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2216
2217 if( consdata->linkingconss != NULL )
2218 {
2219 consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2220 }
2221 }
2222
2223 consdata->nvars--;
2224 consdata->validsignature = FALSE;
2225 consdata->normalized = FALSE;
2226
2227 return SCIP_OKAY;
2228}
2229
2230/** collect linking constraints for each integer variable */
2231static
2233 SCIP* scip, /**< SCIP data structure */
2234 SCIP_CONSDATA* consdata /**< pointer to consdata */
2235 )
2236{
2237 int nvars;
2238 int v;
2239
2240 assert(scip != NULL);
2241 assert(consdata != NULL);
2242
2243 nvars = consdata->nvars;
2244 assert(nvars > 0);
2245 assert(consdata->linkingconss == NULL);
2246
2247 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2248
2249 for( v = 0; v < nvars; ++v )
2250 {
2251 SCIP_CONS* cons;
2252 SCIP_VAR* var;
2253
2254 var = consdata->vars[v];
2255 assert(var != NULL);
2256
2257 SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2258
2259 /* create linking constraint if it does not exist yet */
2260 if( !SCIPexistsConsLinking(scip, var) )
2261 {
2262 char name[SCIP_MAXSTRLEN];
2263
2264 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2265
2266 /* creates and captures an linking constraint */
2267 SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2268 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2269 SCIP_CALL( SCIPaddCons(scip, cons) );
2270 consdata->linkingconss[v] = cons;
2271 }
2272 else
2273 {
2274 consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2275 SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2276 }
2277
2278 assert(SCIPexistsConsLinking(scip, var));
2279 assert(consdata->linkingconss[v] != NULL);
2280 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2281 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2282 }
2283
2284 return SCIP_OKAY;
2285}
2286
2287/**@} */
2288
2289
2290/**@name Check methods
2291 *
2292 * @{
2293 */
2294
2295/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2296 * given solution is satisfied
2297 */
2298static
2300 SCIP* scip, /**< SCIP data structure */
2301 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2302 int nvars, /**< number of variables (jobs) */
2303 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2304 int* durations, /**< array containing corresponding durations */
2305 int* demands, /**< array containing corresponding demands */
2306 int capacity, /**< available cumulative capacity */
2307 int hmin, /**< left bound of time axis to be considered (including hmin) */
2308 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2309 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2310 SCIP_CONS* cons, /**< constraint which is checked */
2311 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2312 )
2313{
2314 int* startsolvalues; /* stores when each job is starting */
2315 int* endsolvalues; /* stores when each job ends */
2316 int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2317 int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2318
2319 int freecapacity;
2320 int curtime; /* point in time which we are just checking */
2321 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2322 int j;
2323
2324 SCIP_Real absviol;
2325 SCIP_Real relviol;
2326
2327 assert(scip != NULL);
2328 assert(violated != NULL);
2329
2330 (*violated) = FALSE;
2331
2332 if( nvars == 0 )
2333 return SCIP_OKAY;
2334
2335 assert(vars != NULL);
2336 assert(demands != NULL);
2337 assert(durations != NULL);
2338
2339 /* compute time points where we have to check whether capacity constraint is infeasible or not */
2340 SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2341 SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2342 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2343 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2344
2345 /* assign variables, start and endpoints to arrays */
2346 for ( j = 0; j < nvars; ++j )
2347 {
2348 int solvalue;
2349
2350 /* the constraint of the cumulative constraint handler should be called after the integrality check */
2351 assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2352
2353 solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2354
2355 /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2356 * jobs which start before hmin to hmin
2357 */
2358 startsolvalues[j] = MAX(solvalue, hmin);
2359 startindices[j] = j;
2360
2361 endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2362 endindices[j] = j;
2363 }
2364
2365 /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2366 * corresponding indices in the same way)
2367 */
2368 SCIPsortIntInt(startsolvalues, startindices, nvars);
2369 SCIPsortIntInt(endsolvalues, endindices, nvars);
2370
2371 endindex = 0;
2372 freecapacity = capacity;
2373 absviol = 0.0;
2374 relviol = 0.0;
2375
2376 /* check each start point of a job whether the capacity is kept or not */
2377 for( j = 0; j < nvars; ++j )
2378 {
2379 /* only check intervals [hmin,hmax) */
2380 curtime = startsolvalues[j];
2381
2382 if( curtime >= hmax )
2383 break;
2384
2385 /* subtract all capacity needed up to this point */
2386 freecapacity -= demands[startindices[j]];
2387 while( j+1 < nvars && startsolvalues[j+1] == curtime )
2388 {
2389 j++;
2390 freecapacity -= demands[startindices[j]];
2391 }
2392
2393 /* free all capacity usages of jobs that are no longer running */
2394 while( endindex < nvars && curtime >= endsolvalues[endindex] )
2395 {
2396 freecapacity += demands[endindices[endindex]];
2397 ++endindex;
2398 }
2399 assert(freecapacity <= capacity);
2400
2401 /* update absolute and relative violation */
2402 if( absviol < (SCIP_Real) (-freecapacity) )
2403 {
2404 absviol = -freecapacity;
2405 relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2406 }
2407
2408 /* check freecapacity to be smaller than zero */
2409 if( freecapacity < 0 && curtime >= hmin )
2410 {
2411 SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2412 (*violated) = TRUE;
2413
2414 if( printreason )
2415 {
2416 int i;
2417
2418 /* first state the violated constraints */
2419 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2420
2421 /* second state the reason */
2423 ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2424 curtime, capacity, capacity - freecapacity);
2425
2426 for( i = 0; i <= j; ++i )
2427 {
2428 if( startsolvalues[i] + durations[startindices[i]] > curtime )
2429 {
2430 SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2431 SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2432 demands[startindices[i]]);
2433 }
2434 }
2435 }
2436 break;
2437 }
2438 } /*lint --e{850}*/
2439
2440 /* update constraint violation in solution */
2441 if( sol != NULL )
2442 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2443
2444 /* free all buffer arrays */
2445 SCIPfreeBufferArray(scip, &endindices);
2446 SCIPfreeBufferArray(scip, &startindices);
2447 SCIPfreeBufferArray(scip, &endsolvalues);
2448 SCIPfreeBufferArray(scip, &startsolvalues);
2449
2450 return SCIP_OKAY;
2451}
2452
2453/** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2454 * least zero or not. If not (*violated) is set to TRUE
2455 */
2456static
2458 SCIP* scip, /**< SCIP data structure */
2459 SCIP_CONS* cons, /**< constraint to be checked */
2460 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2461 SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2462 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2463 )
2464{
2465 SCIP_CONSDATA* consdata;
2466
2467 assert(scip != NULL);
2468 assert(cons != NULL);
2469 assert(violated != NULL);
2470
2471 SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2472
2473 consdata = SCIPconsGetData(cons);
2474 assert(consdata != NULL);
2475
2476 /* check the cumulative condition */
2477 SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2478 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2479 violated, cons, printreason) );
2480
2481 return SCIP_OKAY;
2482}
2483
2484/**@} */
2485
2486/**@name Conflict analysis
2487 *
2488 * @{
2489 */
2490
2491/** resolves the propagation of the core time algorithm */
2492static
2494 SCIP* scip, /**< SCIP data structure */
2495 int nvars, /**< number of start time variables (activities) */
2496 SCIP_VAR** vars, /**< array of start time variables */
2497 int* durations, /**< array of durations */
2498 int* demands, /**< array of demands */
2499 int capacity, /**< cumulative capacity */
2500 int hmin, /**< left bound of time axis to be considered (including hmin) */
2501 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2502 SCIP_VAR* infervar, /**< inference variable */
2503 int inferdemand, /**< demand of the inference variable */
2504 int inferpeak, /**< time point which causes the propagation */
2505 int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2506 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2507 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2508 int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2509 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2510 )
2511{
2512 SCIP_VAR* var;
2513 SCIP_Bool* reported;
2514 int duration;
2515 int maxlst;
2516 int minect;
2517 int ect;
2518 int lst;
2519 int j;
2520
2522
2523 SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2524 SCIPvarGetName(infervar), inferdemand, inferpeak);
2525 assert(nvars > 0);
2526
2527 /* adjusted capacity */
2528 capacity -= inferdemand;
2529 maxlst = INT_MIN;
2530 minect = INT_MAX;
2531
2532 SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2533 BMSclearMemoryArray(reported, nvars);
2534
2535 /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2536 * inference peak and those where the current conflict bounds provide a core at the inference peak
2537 */
2538 for( j = 0; j < nvars && capacity >= 0; ++j )
2539 {
2540 var = vars[j];
2541 assert(var != NULL);
2542
2543 /* skip inference variable */
2544 if( var == infervar )
2545 continue;
2546
2547 duration = durations[j];
2548 assert(duration > 0);
2549
2550 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2551 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2552 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2553 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2554 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2555
2556 SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2558 SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2559
2560 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2562
2563 /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2564 * that job without adding it the explanation
2565 */
2566 if( inferpeak < ect && lst <= inferpeak )
2567 {
2568 capacity -= demands[j];
2569 reported[j] = TRUE;
2570
2571 maxlst = MAX(maxlst, lst);
2572 minect = MIN(minect, ect);
2573 assert(maxlst < minect);
2574
2575 if( explanation != NULL )
2576 explanation[j] = TRUE;
2577
2578 continue;
2579 }
2580
2581 /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2582 * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2583 * not part of the conflict yet we get the global bounds back.
2584 */
2585 ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2587
2588 /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2589 * of that job without and collect the job as part of the explanation
2590 *
2591 * @note we do not need to reported that job to SCIP since the required bounds are already reported
2592 */
2593 if( inferpeak < ect && lst <= inferpeak )
2594 {
2595 capacity -= demands[j];
2596 reported[j] = TRUE;
2597
2598 maxlst = MAX(maxlst, lst);
2599 minect = MIN(minect, ect);
2600 assert(maxlst < minect);
2601
2602 if( explanation != NULL )
2603 explanation[j] = TRUE;
2604 }
2605 }
2606
2607 if( capacity >= 0 )
2608 {
2609 int* cands;
2610 int* canddemands;
2611 int ncands;
2612 int c;
2613
2614 SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2615 SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2616 ncands = 0;
2617
2618 /* collect all cores of the variables which lay in the considered time window except the inference variable */
2619 for( j = 0; j < nvars; ++j )
2620 {
2621 var = vars[j];
2622 assert(var != NULL);
2623
2624 /* skip inference variable */
2625 if( var == infervar || reported[j] )
2626 continue;
2627
2628 duration = durations[j];
2629 assert(duration > 0);
2630
2631 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2632 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2633 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2634 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2635 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2636
2637 /* collect local core information */
2638 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2639 lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2640
2641 SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2642 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2643 SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2644
2645 /* check if the inference peak is part of the core */
2646 if( inferpeak < ect && lst <= inferpeak )
2647 {
2648 cands[ncands] = j;
2649 canddemands[ncands] = demands[j];
2650 ncands++;
2651
2652 capacity -= demands[j];
2653 }
2654 }
2655
2656 /* sort candidates indices w.r.t. their demands */
2657 SCIPsortDownIntInt(canddemands, cands, ncands);
2658
2659 assert(capacity < 0);
2660 assert(ncands > 0);
2661
2662 /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2663 while( capacity + canddemands[ncands-1] < 0 )
2664 {
2665 ncands--;
2666 capacity += canddemands[ncands];
2667 assert(ncands > 0);
2668 }
2669
2670 /* compute the size (number of time steps) of the job cores */
2671 for( c = 0; c < ncands; ++c )
2672 {
2673 var = vars[cands[c]];
2674 assert(var != NULL);
2675
2676 duration = durations[cands[c]];
2677
2678 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2679 lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2680
2681 maxlst = MAX(maxlst, lst);
2682 minect = MIN(minect, ect);
2683 assert(maxlst < minect);
2684 }
2685
2686 SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2687 assert(inferpeak >= maxlst);
2688 assert(inferpeak < minect);
2689
2690 /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2691 if( relaxedpeak < inferpeak )
2692 {
2693 inferpeak = MAX(maxlst, relaxedpeak);
2694 }
2695 else if( relaxedpeak > inferpeak )
2696 {
2697 inferpeak = MIN(minect-1, relaxedpeak);
2698 }
2699 assert(inferpeak >= hmin);
2700 assert(inferpeak < hmax);
2701 assert(inferpeak >= maxlst);
2702 assert(inferpeak < minect);
2703
2704 /* post all necessary bound changes */
2705 for( c = 0; c < ncands; ++c )
2706 {
2707 var = vars[cands[c]];
2708 assert(var != NULL);
2709
2710 if( usebdwidening )
2711 {
2712 duration = durations[cands[c]];
2713
2714 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2715 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2716 }
2717 else
2718 {
2719 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2720 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2721 }
2722
2723 if( explanation != NULL )
2724 explanation[cands[c]] = TRUE;
2725 }
2726
2727 SCIPfreeBufferArray(scip, &canddemands);
2728 SCIPfreeBufferArray(scip, &cands);
2729 }
2730
2731 SCIPfreeBufferArray(scip, &reported);
2732
2733 if( provedpeak != NULL )
2734 *provedpeak = inferpeak;
2735
2736 return SCIP_OKAY;
2737}
2738
2739#if 0
2740/** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2741 * energy in total and for bound change is enough
2742 */
2743static
2744SCIP_RETCODE resolvePropagationEdgeFinding(
2745 SCIP* scip, /**< SCIP data structure */
2746 int nvars, /**< number of start time variables (activities) */
2747 SCIP_VAR** vars, /**< array of start time variables */
2748 int* durations, /**< array of durations */
2749 int hmin, /**< left bound of time axis to be considered (including hmin) */
2750 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2751 SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2752 INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2753 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2754 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2755 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2756 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2757 )
2758{
2759 int est;
2760 int lct;
2761 int j;
2762
2763 /* ???????????????????? do bound widening */
2764
2765 assert(scip != NULL);
2766 assert(nvars > 0);
2767 assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2768
2769 SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2770
2771 if( boundtype == SCIP_BOUNDTYPE_LOWER )
2772 {
2773 SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2774 }
2775 else
2776 {
2777 SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2778 }
2779
2780 est = inferInfoGetData1(inferinfo);
2781 lct = inferInfoGetData2(inferinfo);
2782 assert(est < lct);
2783
2784 /* collect the energies of all variables in [est_omega, lct_omega] */
2785 for( j = 0; j < nvars; ++j )
2786 {
2787 SCIP_VAR* var;
2788 SCIP_Bool left;
2789 SCIP_Bool right;
2790 int duration;
2791 int lb;
2792 int ub;
2793
2794 var = vars[j];
2795 assert(var != NULL);
2796
2797 if( var == infervar )
2798 {
2799 if( explanation != NULL )
2800 explanation[j] = TRUE;
2801
2802 continue;
2803 }
2804
2805 lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2806 ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2807
2808 duration = durations[j];
2809 assert(duration > 0);
2810
2811 /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2812 * since we use adjusted jobs during the propagation
2813 */
2814 left = (est == hmin && lb + duration > hmin) || lb >= est;
2815
2816 /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2817 * since we use adjusted jobs during the propagation
2818 */
2819 right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2820
2821 /* store all jobs running in [est_omega; lct_omega] */
2822 if( left && right )
2823 {
2824 /* check if bound widening should be used */
2825 if( usebdwidening )
2826 {
2827 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2828 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2829 }
2830 else
2831 {
2832 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2833 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2834 }
2835
2836 if( explanation != NULL )
2837 explanation[j] = TRUE;
2838 }
2839 }
2840
2841 return SCIP_OKAY;
2842}
2843#endif
2844
2845/** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2846static
2848 int begin, /**< begin of the times interval */
2849 int end, /**< end of time interval */
2850 int est, /**< earliest start time */
2851 int lst, /**< latest start time */
2852 int duration /**< duration of the job */
2853 )
2854{
2855 int left;
2856 int right;
2857 int ect;
2858 int lct;
2859
2860 ect = est + duration;
2861 lct = lst + duration;
2862
2863 /* check if job runs completely within [begin,end) */
2864 if( lct <= end && est >= begin )
2865 return duration;
2866
2867 assert(lst <= end && ect >= begin);
2868
2869 left = ect - begin;
2870 assert(left > 0);
2871
2872 right = end - lst;
2873 assert(right > 0);
2874
2875 return MIN3(left, right, end - begin);
2876}
2877
2878/** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2879 * reason
2880 *
2881 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2882 */
2883static
2885 SCIP* scip, /**< SCIP data structure */
2886 int nvars, /**< number of start time variables (activities) */
2887 SCIP_VAR** vars, /**< array of start time variables */
2888 int* durations, /**< array of durations */
2889 int* demands, /**< array of demands */
2890 int capacity, /**< capacity of the cumulative condition */
2891 int begin, /**< begin of the time window */
2892 int end, /**< end of the time window */
2893 SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2894 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2895 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2896 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2897 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2898 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2899 )
2900{
2901 int* locenergies;
2902 int* overlaps;
2903 int* idxs;
2904
2905 SCIP_Longint requiredenergy;
2906 int v;
2907
2908 SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2909 SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2910 SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2911
2912 /* energy which needs be explained */
2913 requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2914
2915 SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2916
2917 /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2918 * takes
2919 */
2920 for( v = 0; v < nvars; ++v )
2921 {
2922 SCIP_VAR* var;
2923 int glbenergy;
2924 int duration;
2925 int demand;
2926 int est;
2927 int lst;
2928
2929 var = vars[v];
2930 assert(var != NULL);
2931
2932 locenergies[v] = 0;
2933 overlaps[v] = 0;
2934 idxs[v] = v;
2935
2936 demand = demands[v];
2937 assert(demand > 0);
2938
2939 duration = durations[v];
2940 assert(duration > 0);
2941
2942 /* check if the variable equals the inference variable (the one which was propagated) */
2943 if( infervar == var )
2944 {
2945 int overlap;
2946 int right;
2947 int left;
2948
2949 assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2950
2951 SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2952 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2953 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2954
2955 /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2956 * which is necessary from the inference variable
2957 */
2958 if( boundtype == SCIP_BOUNDTYPE_UPPER )
2959 {
2960 int lct;
2961
2962 /* get the latest start time of the infer start time variable before the propagation took place */
2963 lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2964
2965 /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2966 * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2967 * scheduled w.r.t. its latest start time
2968 */
2969 assert(lst < end);
2970
2971 /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2972 * interval (before the propagation)
2973 */
2974 right = MIN3(end - lst, end - begin, duration);
2975
2976 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2977 assert(right > 0);
2978
2979 lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2980 assert(begin <= lct);
2981 assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2982
2983 /* compute the overlap of the job after the propagation but considering the relaxed bound */
2984 left = MIN(lct - begin + 1, end - begin);
2985 assert(left > 0);
2986
2987 /* compute the minimum overlap; */
2988 overlap = MIN(left, right);
2989 assert(overlap > 0);
2990 assert(overlap <= end - begin);
2991 assert(overlap <= duration);
2992
2993 if( usebdwidening )
2994 {
2995 assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2996 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2997 }
2998 else
2999 {
3000 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
3001 }
3002 }
3003 else
3004 {
3005 int ect;
3006
3007 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3008
3009 /* get the earliest completion time of the infer start time variable before the propagation took place */
3010 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
3011
3012 /* the earliest start time of the inference start time variable before the propagation needs to be larger as
3013 * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
3014 * the job is scheduled w.r.t. its earliest start time
3015 */
3016 assert(ect > begin);
3017
3018 /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
3019 * interval (before the propagation)
3020 */
3021 left = MIN3(ect - begin, end - begin, duration);
3022
3023 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
3024 assert(left > 0);
3025
3026 est = SCIPconvertRealToInt(scip, relaxedbd);
3027 assert(end >= est);
3028 assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
3029
3030 /* compute the overlap of the job after the propagation but considering the relaxed bound */
3031 right = MIN(end - est + 1, end - begin);
3032 assert(right > 0);
3033
3034 /* compute the minimum overlap */
3035 overlap = MIN(left, right);
3036 assert(overlap > 0);
3037 assert(overlap <= end - begin);
3038 assert(overlap <= duration);
3039
3040 if( usebdwidening )
3041 {
3042 assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3043 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3044 }
3045 else
3046 {
3047 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3048 }
3049 }
3050
3051 /* subtract the amount of energy which is available due to the overlap of the inference start time */
3052 requiredenergy -= (SCIP_Longint) overlap * demand;
3053
3054 if( explanation != NULL )
3055 explanation[v] = TRUE;
3056
3057 continue;
3058 }
3059
3060 /* global time points */
3063
3064 glbenergy = 0;
3065
3066 /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3067 * time window
3068 */
3069 if( est + duration > begin && lst < end )
3070 {
3071 /* evaluated global contribution */
3072 glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3073
3074 /* remove the globally available energy form the required energy */
3075 requiredenergy -= glbenergy;
3076
3077 if( explanation != NULL )
3078 explanation[v] = TRUE;
3079 }
3080
3081 /* local time points */
3082 est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3083 lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3084
3085 /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3086 * time window
3087 */
3088 if( est + duration > begin && lst < end )
3089 {
3090 overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3091
3092 /* evaluated additionally local energy contribution */
3093 locenergies[v] = overlaps[v] * demand - glbenergy;
3094 assert(locenergies[v] >= 0);
3095 }
3096 }
3097
3098 /* sort the variable contributions w.r.t. additional local energy contributions */
3099 SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3100
3101 /* add local energy contributions until an overload is implied */
3102 for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3103 {
3104 SCIP_VAR* var;
3105 int duration;
3106 int overlap;
3107 int relaxlb;
3108 int relaxub;
3109 int idx;
3110
3111 idx = idxs[v];
3112 assert(idx >= 0 && idx < nvars);
3113
3114 var = vars[idx];
3115 assert(var != NULL);
3116 assert(var != infervar);
3117
3118 duration = durations[idx];
3119 assert(duration > 0);
3120
3121 overlap = overlaps[v];
3122 assert(overlap > 0);
3123
3124 requiredenergy -= locenergies[v];
3125
3126 if( requiredenergy < -1 )
3127 {
3128 int demand;
3129
3130 demand = demands[idx];
3131 assert(demand > 0);
3132
3133 overlap += (int)((requiredenergy + 1) / demand);
3134
3135#ifndef NDEBUG
3136 requiredenergy += locenergies[v];
3137 requiredenergy -= (SCIP_Longint) overlap * demand;
3138 assert(requiredenergy < 0);
3139#endif
3140 }
3141 assert(overlap > 0);
3142
3143 relaxlb = begin - duration + overlap;
3144 relaxub = end - overlap;
3145
3146 SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3147 SCIPvarGetName(var),
3151 relaxlb, relaxub, demands[idx], duration);
3152
3153 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3154 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3155
3156 if( explanation != NULL )
3157 explanation[idx] = TRUE;
3158 }
3159
3160 assert(requiredenergy < 0);
3161
3162 SCIPfreeBufferArray(scip, &idxs);
3163 SCIPfreeBufferArray(scip, &overlaps);
3164 SCIPfreeBufferArray(scip, &locenergies);
3165
3166 return SCIP_OKAY;
3167}
3168
3169/** resolve propagation w.r.t. the cumulative condition */
3170static
3172 SCIP* scip, /**< SCIP data structure */
3173 int nvars, /**< number of start time variables (activities) */
3174 SCIP_VAR** vars, /**< array of start time variables */
3175 int* durations, /**< array of durations */
3176 int* demands, /**< array of demands */
3177 int capacity, /**< cumulative capacity */
3178 int hmin, /**< left bound of time axis to be considered (including hmin) */
3179 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3180 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3181 INFERINFO inferinfo, /**< the user information */
3182 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3183 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3184 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3185 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3186 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3187 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3188 )
3189{
3190 switch( inferInfoGetProprule(inferinfo) )
3191 {
3193 {
3194 int inferdemand;
3195 int inferduration;
3196 int inferpos;
3197 int inferpeak;
3198 int relaxedpeak;
3199 int provedpeak;
3200
3201 /* get the position of the inferred variable in the vars array */
3202 inferpos = inferInfoGetData1(inferinfo);
3203 if( inferpos >= nvars || vars[inferpos] != infervar )
3204 {
3205 /* find inference variable in constraint */
3206 for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3207 {}
3208 }
3209 assert(inferpos < nvars);
3210 assert(vars[inferpos] == infervar);
3211
3212 inferdemand = demands[inferpos];
3213 inferduration = durations[inferpos];
3214
3215 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3216 {
3217 /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3218 * the inference variable
3219 */
3220 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3221
3222 SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3223 SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3224 SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3225
3226 /* get the inference peak that the time point which lead to the that propagtion */
3227 inferpeak = inferInfoGetData2(inferinfo);
3228 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3229 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3230 */
3231 assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3232 relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3233
3234 /* make sure that the relaxed peak is part of the effective horizon */
3235 relaxedpeak = MIN(relaxedpeak, hmax-1);
3236
3237 /* make sure that relaxed peak is not larger than the infer peak
3238 *
3239 * This can happen in case the variable is not an active variable!
3240 */
3241 relaxedpeak = MAX(relaxedpeak, inferpeak);
3242 assert(relaxedpeak >= inferpeak);
3243 assert(relaxedpeak >= hmin);
3244 }
3245 else
3246 {
3247 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3248
3249 SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3250 SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3251 SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3252
3253 /* get the time interval where the job could not be scheduled */
3254 inferpeak = inferInfoGetData2(inferinfo);
3255 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3256 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3257 */
3258 assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3259 relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3260
3261 /* make sure that the relaxed peak is part of the effective horizon */
3262 relaxedpeak = MAX(relaxedpeak, hmin);
3263
3264 /* make sure that relaxed peak is not larger than the infer peak
3265 *
3266 * This can happen in case the variable is not an active variable!
3267 */
3268 relaxedpeak = MIN(relaxedpeak, inferpeak);
3269 assert(relaxedpeak < hmax);
3270 }
3271
3272 /* resolves the propagation of the core time algorithm */
3273 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3274 infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3275
3276 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3277 {
3278 if( usebdwidening )
3279 {
3280 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3281 }
3282 else
3283 {
3284 /* old upper bound of variable itself is part of the explanation */
3285 SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3286 }
3287 }
3288 else
3289 {
3290 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3291
3292 if( usebdwidening )
3293 {
3294 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3295 }
3296 else
3297 {
3298 /* old lower bound of variable itself is part of the explanation */
3299 SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3300 }
3301 }
3302
3303 if( explanation != NULL )
3304 explanation[inferpos] = TRUE;
3305
3306 break;
3307 }
3309 case PROPRULE_3_TTEF:
3310 {
3311 int begin;
3312 int end;
3313
3314 begin = inferInfoGetData1(inferinfo);
3315 end = inferInfoGetData2(inferinfo);
3316 assert(begin < end);
3317
3318 begin = MAX(begin, hmin);
3319 end = MIN(end, hmax);
3320
3321 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3322 begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3323
3324 break;
3325 }
3326
3327 case PROPRULE_0_INVALID:
3328 default:
3329 SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3330 SCIPABORT();
3331 return SCIP_INVALIDDATA; /*lint !e527*/
3332 }
3333
3334 (*result) = SCIP_SUCCESS;
3335
3336 return SCIP_OKAY;
3337}
3338
3339/**@} */
3340
3341
3342/**@name Enforcement methods
3343 *
3344 * @{
3345 */
3346
3347/** apply all fixings which are given by the alternative bounds */
3348static
3350 SCIP* scip, /**< SCIP data structure */
3351 SCIP_VAR** vars, /**< array of active variables */
3352 int nvars, /**< number of active variables */
3353 int* alternativelbs, /**< alternative lower bounds */
3354 int* alternativeubs, /**< alternative lower bounds */
3355 int* downlocks, /**< number of constraints with down lock participating by the computation */
3356 int* uplocks, /**< number of constraints with up lock participating by the computation */
3357 SCIP_Bool* branched /**< pointer to store if a branching was applied */
3358 )
3359{
3360 int v;
3361
3362 for( v = 0; v < nvars; ++v )
3363 {
3364 SCIP_VAR* var;
3365 SCIP_Real objval;
3366
3367 var = vars[v];
3368 assert(var != NULL);
3369
3370 objval = SCIPvarGetObj(var);
3371
3372 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3373 {
3374 int ub;
3375
3377
3378 if( alternativelbs[v] <= ub )
3379 {
3380 SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3381 (*branched) = TRUE;
3382
3383 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3384 SCIPvarGetLbLocal(var), alternativelbs[v]);
3385
3386 return SCIP_OKAY;
3387 }
3388 }
3389
3390 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3391 {
3392 int lb;
3393
3395
3396 if( alternativeubs[v] >= lb )
3397 {
3398 SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3399 (*branched) = TRUE;
3400
3401 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3402 alternativeubs[v], SCIPvarGetUbLocal(var));
3403
3404 return SCIP_OKAY;
3405 }
3406 }
3407 }
3408
3409 return SCIP_OKAY;
3410}
3411
3412/** remove the capacity requirments for all job which start at the curtime */
3413static
3415 SCIP_CONSDATA* consdata, /**< constraint data */
3416 int curtime, /**< current point in time */
3417 int* starttimes, /**< array of start times */
3418 int* startindices, /**< permutation with respect to the start times */
3419 int* freecapacity, /**< pointer to store the resulting free capacity */
3420 int* idx, /**< pointer to index in start time array */
3421 int nvars /**< number of vars in array of starttimes and startindices */
3422 )
3423{
3424#if defined SCIP_DEBUG && !defined NDEBUG
3425 int oldidx;
3426
3427 assert(idx != NULL);
3428 oldidx = *idx;
3429#else
3430 assert(idx != NULL);
3431#endif
3432
3433 assert(starttimes != NULL);
3434 assert(starttimes != NULL);
3435 assert(freecapacity != NULL);
3436 assert(starttimes[*idx] == curtime);
3437 assert(consdata->demands != NULL);
3438 assert(freecapacity != idx);
3439
3440 /* subtract all capacity needed up to this point */
3441 (*freecapacity) -= consdata->demands[startindices[*idx]];
3442
3443 while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3444 {
3445 ++(*idx);
3446 (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3447 assert(freecapacity != idx);
3448 }
3449#ifdef SCIP_DEBUG
3450 assert(oldidx <= *idx);
3451#endif
3452}
3453
3454/** add the capacity requirments for all job which end at the curtime */
3455static
3457 SCIP_CONSDATA* consdata, /**< constraint data */
3458 int curtime, /**< current point in time */
3459 int* endtimes, /**< array of end times */
3460 int* endindices, /**< permutation with rspect to the end times */
3461 int* freecapacity, /**< pointer to store the resulting free capacity */
3462 int* idx, /**< pointer to index in end time array */
3463 int nvars /**< number of vars in array of starttimes and startindices */
3464 )
3465{
3466#if defined SCIP_DEBUG && !defined NDEBUG
3467 int oldidx;
3468 oldidx = *idx;
3469#endif
3470
3471 /* free all capacity usages of jobs the are no longer running */
3472 while( endtimes[*idx] <= curtime && *idx < nvars)
3473 {
3474 (*freecapacity) += consdata->demands[endindices[*idx]];
3475 ++(*idx);
3476 }
3477
3478#ifdef SCIP_DEBUG
3479 assert(oldidx <= *idx);
3480#endif
3481}
3482
3483/** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3484static
3486 SCIP* scip, /**< SCIP data structure */
3487 SCIP_CONSDATA* consdata, /**< constraint handler data */
3488 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3489 int* timepoint /**< pointer to store the time point of the peak */
3490 )
3491{
3492 int* starttimes; /* stores when each job is starting */
3493 int* endtimes; /* stores when each job ends */
3494 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3495 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3496
3497 int nvars; /* number of activities for this constraint */
3498 int freecapacity; /* remaining capacity */
3499 int curtime; /* point in time which we are just checking */
3500 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3501
3502 int hmin;
3503 int hmax;
3504
3505 int j;
3506
3507 assert(consdata != NULL);
3508
3509 nvars = consdata->nvars;
3510 assert(nvars > 0);
3511
3512 *timepoint = consdata->hmax;
3513
3514 assert(consdata->vars != NULL);
3515
3516 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3517 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3518 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3519 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3520
3521 /* create event point arrays */
3522 createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3523 starttimes, endtimes, startindices, endindices);
3524
3525 endindex = 0;
3526 freecapacity = consdata->capacity;
3527 hmin = consdata->hmin;
3528 hmax = consdata->hmax;
3529
3530 /* check each startpoint of a job whether the capacity is kept or not */
3531 for( j = 0; j < nvars; ++j )
3532 {
3533 curtime = starttimes[j];
3534 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3535
3536 if( curtime >= hmax )
3537 break;
3538
3539 /* remove the capacity requirments for all job which start at the curtime */
3540 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3541
3542 /* add the capacity requirments for all job which end at the curtime */
3543 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3544
3545 assert(freecapacity <= consdata->capacity);
3546 assert(endindex <= nvars);
3547
3548 /* endindex - points to the next job which will finish */
3549 /* j - points to the last job that has been released */
3550
3551 /* if free capacity is smaller than zero, then add branching candidates */
3552 if( freecapacity < 0 && curtime >= hmin )
3553 {
3554 *timepoint = curtime;
3555 break;
3556 }
3557 } /*lint --e{850}*/
3558
3559 /* free all buffer arrays */
3560 SCIPfreeBufferArray(scip, &endindices);
3561 SCIPfreeBufferArray(scip, &startindices);
3562 SCIPfreeBufferArray(scip, &endtimes);
3563 SCIPfreeBufferArray(scip, &starttimes);
3564
3565 return SCIP_OKAY;
3566}
3567
3568/** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3569static
3571 SCIP* scip, /**< SCIP data structure */
3572 SCIP_CONS** conss, /**< constraints to be processed */
3573 int nconss, /**< number of constraints */
3574 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3575 int* nbranchcands /**< pointer to store the number of branching variables */
3576 )
3577{
3578 SCIP_HASHTABLE* collectedvars;
3579 int c;
3580
3581 assert(scip != NULL);
3582 assert(conss != NULL);
3583
3584 /* create a hash table */
3586 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3587
3588 assert(scip != NULL);
3589 assert(conss != NULL);
3590
3591 for( c = 0; c < nconss; ++c )
3592 {
3593 SCIP_CONS* cons;
3594 SCIP_CONSDATA* consdata;
3595
3596 int curtime;
3597 int j;
3598
3599 cons = conss[c];
3600 assert(cons != NULL);
3601
3602 if( !SCIPconsIsActive(cons) )
3603 continue;
3604
3605 consdata = SCIPconsGetData(cons);
3606 assert(consdata != NULL);
3607
3608 /* get point in time when capacity is exceeded */
3609 SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3610
3611 if( curtime < consdata->hmin || curtime >= consdata->hmax )
3612 continue;
3613
3614 /* report all variables that are running at that point in time */
3615 for( j = 0; j < consdata->nvars; ++j )
3616 {
3617 SCIP_VAR* var;
3618 int lb;
3619 int ub;
3620
3621 var = consdata->vars[j];
3622 assert(var != NULL);
3623
3624 /* check if the variable was already added */
3625 if( SCIPhashtableExists(collectedvars, (void*)var) )
3626 continue;
3627
3630
3631 if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3632 {
3633 SCIP_Real solval;
3634 SCIP_Real score;
3635
3636 solval = SCIPgetSolVal(scip, sol, var);
3637 score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3638
3639 SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3640 SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3641 (*nbranchcands)++;
3642
3643 SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3644 }
3645 }
3646 }
3647
3648 SCIPhashtableFree(&collectedvars);
3649
3650 SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3651
3652 return SCIP_OKAY;
3653}
3654
3655/** enforcement of an LP, pseudo, or relaxation solution */
3656static
3658 SCIP* scip, /**< SCIP data structure */
3659 SCIP_CONS** conss, /**< constraints to be processed */
3660 int nconss, /**< number of constraints */
3661 SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3662 SCIP_Bool branch, /**< should branching candidates be collected */
3663 SCIP_RESULT* result /**< pointer to store the result */
3664 )
3665{
3666 if( branch )
3667 {
3668 int nbranchcands;
3669
3670 nbranchcands = 0;
3671 SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3672
3673 if( nbranchcands > 0 )
3674 (*result) = SCIP_INFEASIBLE;
3675 }
3676 else
3677 {
3678 SCIP_Bool violated;
3679 int c;
3680
3681 violated = FALSE;
3682
3683 /* first check if a constraints is violated */
3684 for( c = 0; c < nconss && !violated; ++c )
3685 {
3686 SCIP_CONS* cons;
3687
3688 cons = conss[c];
3689 assert(cons != NULL);
3690
3691 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3692 }
3693
3694 if( violated )
3695 (*result) = SCIP_INFEASIBLE;
3696 }
3697
3698 return SCIP_OKAY;
3699}
3700
3701/**@} */
3702
3703/**@name Propagation
3704 *
3705 * @{
3706 */
3707
3708/** check if cumulative constraint is independently of all other constraints */
3709static
3711 SCIP_CONS* cons /**< cumulative constraint */
3712 )
3713{
3714 SCIP_CONSDATA* consdata;
3715 SCIP_VAR** vars;
3716 SCIP_Bool* downlocks;
3717 SCIP_Bool* uplocks;
3718 int nvars;
3719 int v;
3720
3721 consdata = SCIPconsGetData(cons);
3722 assert(consdata != NULL);
3723
3724 nvars = consdata->nvars;
3725 vars = consdata->vars;
3726 downlocks = consdata->downlocks;
3727 uplocks = consdata->uplocks;
3728
3729 /* check if the cumulative constraint has the only locks on the involved variables */
3730 for( v = 0; v < nvars; ++v )
3731 {
3732 SCIP_VAR* var;
3733
3734 var = vars[v];
3735 assert(var != NULL);
3736
3737 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3738 || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3739 return FALSE;
3740 }
3741
3742 return TRUE;
3743}
3744
3745/** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3746 * (dual reductions)
3747 */
3748static
3750 SCIP* scip, /**< SCIP data structure */
3751 SCIP_CONS* cons, /**< cumulative constraint */
3752 SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3753 int* nchgbds, /**< pointer to store the number changed variable bounds */
3754 int* nfixedvars, /**< pointer to count number of fixings */
3755 int* ndelconss, /**< pointer to count number of deleted constraints */
3756 SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3757 SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3758 )
3759{
3760 SCIP_CONSDATA* consdata;
3761 SCIP_VAR** vars;
3762 SCIP_Real* objvals;
3763 SCIP_Real* lbs;
3764 SCIP_Real* ubs;
3765 SCIP_Real timelimit;
3766 SCIP_Real memorylimit;
3767 SCIP_Bool solved;
3768 SCIP_Bool error;
3769
3770 int ncheckconss;
3771 int nvars;
3772 int v;
3773
3774 assert(scip != NULL);
3775 assert(!SCIPconsIsModifiable(cons));
3776 assert(SCIPgetNConss(scip) > 0);
3777
3778 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3779 * would/could end in an implication which can lead to cutoff of the/all optimal solution
3780 */
3782 return SCIP_OKAY;
3783
3784 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3785 * use the locks to decide for a dual reduction using this constraint;
3786 */
3787 if( !SCIPconsIsChecked(cons) )
3788 return SCIP_OKAY;
3789
3790 ncheckconss = SCIPgetNCheckConss(scip);
3791
3792 /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3793 * presolved problem do nothing execpt to change the parameter settings
3794 */
3795 if( ncheckconss == 1 )
3796 {
3797 /* shrink the minimal maximum value for the conflict length */
3798 SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3799
3800 /* use only first unique implication point */
3801 SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3802
3803 /* do not use reconversion conflicts */
3804 SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3805
3806 /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3807 SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3808
3809 /* increase the number of conflicts which induce a restart */
3810 SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3811
3812 /* weight the variable which made into a conflict */
3813 SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3814
3815 /* do not check pseudo solution (for performance reasons) */
3816 SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3817
3818 /* use value based history to detect a reasonable branching point */
3819 SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3820
3821 /* turn of LP relaxation */
3822 SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3823
3824 /* prefer the down branch in case the value based history does not suggest something */
3825 SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3826
3827 /* accept any bound change */
3828 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3829
3830 /* allow for at most 10 restart, after that the value based history should be reliable */
3831 SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3832
3833 /* set priority for depth first search to highest possible value */
3834 SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3835
3836 return SCIP_OKAY;
3837 }
3838
3839 consdata = SCIPconsGetData(cons);
3840 assert(consdata != NULL);
3841
3842 /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3843 * fail on the first place
3844 */
3845 if( consdata->triedsolving )
3846 return SCIP_OKAY;
3847
3848 /* check if constraint is independently */
3849 if( !isConsIndependently(cons) )
3850 return SCIP_OKAY;
3851
3852 /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3853 * constraint is deleted; otherwise, we want to ensure that we do not try that again
3854 */
3855 consdata->triedsolving = TRUE;
3856
3857 SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3860
3861 nvars = consdata->nvars;
3862 vars = consdata->vars;
3863
3864 SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3865 SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3866 SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3867
3868 for( v = 0; v < nvars; ++v )
3869 {
3870 SCIP_VAR* var;
3871
3872 /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3873 * array
3874 */
3875 var = vars[v];
3876 assert(var != NULL);
3877
3878 lbs[v] = SCIPvarGetLbLocal(var);
3879 ubs[v] = SCIPvarGetUbLocal(var);
3880
3881 objvals[v] = SCIPvarGetObj(var);
3882 }
3883
3884 /* check whether there is enough time and memory left */
3885 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3886 if( !SCIPisInfinity(scip, timelimit) )
3887 timelimit -= SCIPgetSolvingTime(scip);
3888 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3889
3890 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3891 if( !SCIPisInfinity(scip, memorylimit) )
3892 {
3893 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3894 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3895 }
3896
3897 /* solve the cumulative condition separately */
3898 SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3899 consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3900
3901 if( !(*cutoff) && !(*unbounded) && !error )
3902 {
3903 SCIP_Bool infeasible;
3904 SCIP_Bool tightened;
3905 SCIP_Bool allfixed;
3906
3907 allfixed = TRUE;
3908
3909 for( v = 0; v < nvars; ++v )
3910 {
3911 /* check if variable is fixed */
3912 if( lbs[v] + 0.5 > ubs[v] )
3913 {
3914 SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3915 assert(!infeasible);
3916
3917 if( tightened )
3918 {
3919 (*nfixedvars)++;
3920 consdata->triedsolving = FALSE;
3921 }
3922 }
3923 else
3924 {
3925 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3926 assert(!infeasible);
3927
3928 if( tightened )
3929 {
3930 (*nchgbds)++;
3931 consdata->triedsolving = FALSE;
3932 }
3933
3934 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3935 assert(!infeasible);
3936
3937 if( tightened )
3938 {
3939 (*nchgbds)++;
3940 consdata->triedsolving = FALSE;
3941 }
3942
3943 allfixed = FALSE;
3944 }
3945 }
3946
3947 /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3948 if( allfixed )
3949 {
3951 (*ndelconss)++;
3952 }
3953 }
3954
3955 SCIPfreeBufferArray(scip, &objvals);
3958
3959 return SCIP_OKAY;
3960}
3961
3962/** start conflict analysis to analysis the core insertion which is infeasible */
3963static
3965 SCIP* scip, /**< SCIP data structure */
3966 int nvars, /**< number of start time variables (activities) */
3967 SCIP_VAR** vars, /**< array of start time variables */
3968 int* durations, /**< array of durations */
3969 int* demands, /**< array of demands */
3970 int capacity, /**< cumulative capacity */
3971 int hmin, /**< left bound of time axis to be considered (including hmin) */
3972 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3973 SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3974 int inferduration, /**< duration of the start time variable */
3975 int inferdemand, /**< demand of the start time variable */
3976 int inferpeak, /**< profile preak which causes the infeasibilty */
3977 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3978 SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3979 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3980 )
3981{
3982 SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3983 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3984 SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3985
3986 /* initialize conflict analysis if conflict analysis is applicable */
3988 {
3990
3991 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3992 infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3993
3994 SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3995
3996 /* add both bound of the inference variable since these biuld the core which we could not inserted */
3997 if( usebdwidening )
3998 {
3999 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
4000 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
4001 }
4002 else
4003 {
4004 SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
4005 SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
4006 }
4007
4008 *initialized = TRUE;
4009 }
4010
4011 return SCIP_OKAY;
4012}
4013
4014/** We are using the core resource profile which contains all core except the one of the start time variable which we
4015 * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
4016 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4017 * analysis
4018 */
4019static
4021 SCIP* scip, /**< SCIP data structure */
4022 int nvars, /**< number of start time variables (activities) */
4023 SCIP_VAR** vars, /**< array of start time variables */
4024 int* durations, /**< array of durations */
4025 int* demands, /**< array of demands */
4026 int capacity, /**< cumulative capacity */
4027 int hmin, /**< left bound of time axis to be considered (including hmin) */
4028 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4029 SCIP_CONS* cons, /**< constraint which is propagated */
4030 SCIP_PROFILE* profile, /**< resource profile */
4031 int idx, /**< position of the variable to propagate */
4032 int* nchgbds, /**< pointer to store the number of bound changes */
4033 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
4034 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4035 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4036 SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4037 )
4038{
4039 SCIP_VAR* var;
4040 int ntimepoints;
4041 int duration;
4042 int demand;
4043 int peak;
4044 int newlb;
4045 int est;
4046 int lst;
4047 int pos;
4048
4049 var = vars[idx];
4050 assert(var != NULL);
4051
4052 duration = durations[idx];
4053 assert(duration > 0);
4054
4055 demand = demands[idx];
4056 assert(demand > 0);
4057
4060 ntimepoints = SCIPprofileGetNTimepoints(profile);
4061
4062 /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4063 * load which we have at the earliest start time (lower bound)
4064 */
4065 (void) SCIPprofileFindLeft(profile, est, &pos);
4066
4067 SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4068
4069 /* we now trying to move the earliest start time in steps of at most "duration" length */
4070 do
4071 {
4072 INFERINFO inferinfo;
4073 SCIP_Bool tightened;
4074 int ect;
4075
4076#ifndef NDEBUG
4077 {
4078 /* in debug mode we check that we adjust the search position correctly */
4079 int tmppos;
4080
4081 (void)SCIPprofileFindLeft(profile, est, &tmppos);
4082 assert(pos == tmppos);
4083 }
4084#endif
4085 ect = est + duration;
4086 peak = -1;
4087
4088 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4089 * want a peak which is closest to the earliest completion time
4090 */
4091 do
4092 {
4093 /* check if the profile load conflicts with the demand of the start time variable */
4094 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4095 peak = pos;
4096
4097 pos++;
4098 }
4099 while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4100
4101 /* if we found no peak that means current the job could be scheduled at its earliest start time without
4102 * conflicting to the core resource profile
4103 */
4104 /* coverity[check_after_sink] */
4105 if( peak == -1 )
4106 break;
4107
4108 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4109 * profile. That means we have to move it to the next time point in the resource profile but at most to the
4110 * earliest completion time (the remaining move will done in the next loop)
4111 */
4112 newlb = SCIPprofileGetTime(profile, peak+1);
4113 newlb = MIN(newlb, ect);
4114
4115 /* if the earliest start time is greater than the lst we detected an infeasibilty */
4116 if( newlb > lst )
4117 {
4118 SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4119
4120 /* use conflict analysis to analysis the core insertion which was infeasible */
4121 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4122 var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4123
4124 if( explanation != NULL )
4125 explanation[idx] = TRUE;
4126
4127 *infeasible = TRUE;
4128
4129 break;
4130 }
4131
4132 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4133 * bound change
4134 */
4135 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4136
4137 /* perform the bound lower bound change */
4138 if( inferInfoIsValid(inferinfo) )
4139 {
4140 SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4141 }
4142 else
4143 {
4144 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4145 }
4146 assert(tightened);
4147 assert(!(*infeasible));
4148
4149 SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4150 (*nchgbds)++;
4151
4152 /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4154
4155 /* adjust the earliest start time
4156 *
4157 * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4158 * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4159 * involved.
4160 */
4162 assert(est >= newlb);
4163
4164 /* adjust the search position for the resource profile for the next step */
4165 if( est == SCIPprofileGetTime(profile, peak+1) )
4166 pos = peak + 1;
4167 else
4168 pos = peak;
4169 }
4170 while( est < lst );
4171
4172 return SCIP_OKAY;
4173}
4174
4175/** We are using the core resource profile which contains all core except the one of the start time variable which we
4176 * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4177 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4178 * analysis
4179 */
4180static
4182 SCIP* scip, /**< SCIP data structure */
4183 SCIP_VAR* var, /**< start time variable to propagate */
4184 int duration, /**< duration of the job */
4185 int demand, /**< demand of the job */
4186 int capacity, /**< cumulative capacity */
4187 SCIP_CONS* cons, /**< constraint which is propagated */
4188 SCIP_PROFILE* profile, /**< resource profile */
4189 int idx, /**< position of the variable to propagate */
4190 int* nchgbds /**< pointer to store the number of bound changes */
4191 )
4192{
4193 int ntimepoints;
4194 int newub;
4195 int peak;
4196 int pos;
4197 int est;
4198 int lst;
4199 int lct;
4200
4201 assert(var != NULL);
4202 assert(duration > 0);
4203 assert(demand > 0);
4204
4207
4208 /* in case the start time variable is fixed do nothing */
4209 if( est == lst )
4210 return SCIP_OKAY;
4211
4212 ntimepoints = SCIPprofileGetNTimepoints(profile);
4213
4214 lct = lst + duration;
4215
4216 /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4217 * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4218 * position gives us the load which we have at the latest completion time minus one
4219 */
4220 (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4221
4222 SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4224
4225 if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4226 return SCIP_OKAY;
4227
4228 /* we now trying to move the latest start time in steps of at most "duration" length */
4229 do
4230 {
4231 INFERINFO inferinfo;
4232 SCIP_Bool tightened;
4233 SCIP_Bool infeasible;
4234
4235 peak = -1;
4236
4237#ifndef NDEBUG
4238 {
4239 /* in debug mode we check that we adjust the search position correctly */
4240 int tmppos;
4241
4242 (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4243 assert(pos == tmppos);
4244 }
4245#endif
4246
4247 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4248 * want a peak which is closest to the latest start time
4249 */
4250 do
4251 {
4252 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4253 peak = pos;
4254
4255 pos--;
4256 }
4257 while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4258
4259 /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4260 * to the core resource profile
4261 */
4262 /* coverity[check_after_sink] */
4263 if( peak == -1 )
4264 break;
4265
4266 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4267 * profile. That means the job has be done until that point. Hence that gives us the latest completion
4268 * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4269 * doing in the next loop)
4270 */
4271 newub = SCIPprofileGetTime(profile, peak);
4272 newub = MAX(newub, lst) - duration;
4273 assert(newub >= est);
4274
4275 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4276 * bound change
4277 */
4278 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4279
4280 /* perform the bound upper bound change */
4281 if( inferInfoIsValid(inferinfo) )
4282 {
4283 SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4284 }
4285 else
4286 {
4287 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4288 }
4289 assert(tightened);
4290 assert(!infeasible);
4291
4292 SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4293 (*nchgbds)++;
4294
4295 /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4297
4298 /* adjust the latest start and completion time
4299 *
4300 * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4301 * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4302 * involved.
4303 */
4305 assert(lst <= newub);
4306 lct = lst + duration;
4307
4308 /* adjust the search position for the resource profile for the next step */
4309 if( SCIPprofileGetTime(profile, peak) == lct )
4310 pos = peak - 1;
4311 else
4312 pos = peak;
4313 }
4314 while( est < lst );
4315
4316 return SCIP_OKAY;
4317}
4318
4319/** compute for the different earliest start and latest completion time the core energy of the corresponding time
4320 * points
4321 */
4322static
4324 SCIP_PROFILE* profile, /**< core profile */
4325 int nvars, /**< number of start time variables (activities) */
4326 int* ests, /**< array of sorted earliest start times */
4327 int* lcts, /**< array of sorted latest completion times */
4328 int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4329 int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4330 )
4331{
4332 int ntimepoints;
4333 int energy;
4334 int t;
4335 int v;
4336
4337 ntimepoints = SCIPprofileGetNTimepoints(profile);
4338 t = ntimepoints - 1;
4339 energy = 0;
4340
4341 /* compute core energy after the earliest start time of each job */
4342 for( v = nvars-1; v >= 0; --v )
4343 {
4344 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4345 {
4346 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4347 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4348 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4349 t--;
4350 }
4351 assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4352
4353 /* maybe ests[j] is in-between two timepoints */
4354 if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4355 {
4356 assert(t > 0);
4357 coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4358 }
4359 else
4360 coreEnergyAfterEst[v] = energy;
4361 }
4362
4363 t = ntimepoints - 1;
4364 energy = 0;
4365
4366 /* compute core energy after the latest completion time of each job */
4367 for( v = nvars-1; v >= 0; --v )
4368 {
4369 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4370 {
4371 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4372 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4373 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4374 t--;
4375 }
4376 assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4377
4378 /* maybe lcts[j] is in-between two timepoints */
4379 if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4380 {
4381 assert(t > 0);
4382 coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4383 }
4384 else
4385 coreEnergyAfterLct[v] = energy;
4386 }
4387}
4388
4389/** collect earliest start times, latest completion time, and free energy contributions */
4390static
4392 SCIP* scip, /**< SCIP data structure */
4393 int nvars, /**< number of start time variables (activities) */
4394 SCIP_VAR** vars, /**< array of start time variables */
4395 int* durations, /**< array of durations */
4396 int* demands, /**< array of demands */
4397 int hmin, /**< left bound of time axis to be considered (including hmin) */
4398 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4399 int* permests, /**< array to store the variable positions */
4400 int* ests, /**< array to store earliest start times */
4401 int* permlcts, /**< array to store the variable positions */
4402 int* lcts, /**< array to store latest completion times */
4403 int* ects, /**< array to store earliest completion times of the flexible part of the job */
4404 int* lsts, /**< array to store latest start times of the flexible part of the job */
4405 int* flexenergies /**< array to store the flexible energies of each job */
4406 )
4407{
4408 int v;
4409
4410 for( v = 0; v < nvars; ++ v)
4411 {
4412 int duration;
4413 int leftadjust;
4414 int rightadjust;
4415 int core;
4416 int est;
4417 int lct;
4418 int ect;
4419 int lst;
4420
4421 duration = durations[v];
4422 assert(duration > 0);
4423
4426 ect = est + duration;
4427 lct = lst + duration;
4428
4429 ests[v] = est;
4430 lcts[v] = lct;
4431 permests[v] = v;
4432 permlcts[v] = v;
4433
4434 /* compute core time window which lies within the effective horizon */
4435 core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4436
4437 /* compute the number of time steps the job could run before the effective horizon */
4438 leftadjust = MAX(0, hmin - est);
4439
4440 /* compute the number of time steps the job could run after the effective horizon */
4441 rightadjust = MAX(0, lct - hmax);
4442
4443 /* compute for each job the energy which is flexible; meaning not part of the core */
4444 flexenergies[v] = duration - leftadjust - rightadjust - core;
4445 flexenergies[v] = MAX(0, flexenergies[v]);
4446 flexenergies[v] *= demands[v];
4447 assert(flexenergies[v] >= 0);
4448
4449 /* the earliest completion time of the flexible energy */
4450 ects[v] = MIN(ect, lst);
4451
4452 /* the latest start time of the flexible energy */
4453 lsts[v] = MAX(ect, lst);
4454 }
4455}
4456
4457/** try to tighten the lower bound of the given variable */
4458static
4460 SCIP* scip, /**< SCIP data structure */
4461 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4462 int nvars, /**< number of start time variables (activities) */
4463 SCIP_VAR** vars, /**< array of start time variables */
4464 int* durations, /**< array of durations */
4465 int* demands, /**< array of demands */
4466 int capacity, /**< cumulative capacity */
4467 int hmin, /**< left bound of time axis to be considered (including hmin) */
4468 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4469 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4470 int duration, /**< duration of the job */
4471 int demand, /**< demand of the job */
4472 int est, /**< earliest start time of the job */
4473 int ect, /**< earliest completion time of the flexible part of the job */
4474 int lct, /**< latest completion time of the job */
4475 int begin, /**< begin of the time window under investigation */
4476 int end, /**< end of the time window under investigation */
4477 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4478 int* bestlb, /**< pointer to strope the best lower bound change */
4479 int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4480 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4481 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4482 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4483 )
4484{
4485 int newlb;
4486
4487 assert(begin >= hmin);
4488 assert(end <= hmax);
4489
4490 /* check if the time-table edge-finding should infer bounds */
4491 if( !conshdlrdata->ttefinfer )
4492 return SCIP_OKAY;
4493
4494 /* if the job can be processed completely before or after the time window, nothing can be tightened */
4495 if( est >= end || ect <= begin )
4496 return SCIP_OKAY;
4497
4498 /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4499 * skip since the overload check will do the job
4500 */
4501 if( est >= begin && ect <= end )
4502 return SCIP_OKAY;
4503
4504 /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4505 * earliest start time
4506 */
4507 if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4508 return SCIP_OKAY;
4509
4510 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4511 * present; therefore, we need to add the core;
4512 *
4513 * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4514 * compute the earliest completion time of the (whole) job
4515 */
4516 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4517
4518 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4519 *
4520 * @note we can round down the compute duration w.r.t. the available energy
4521 */
4522 newlb = end - (int) (energy / demand);
4523
4524 /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4525 * bound (latest start time); meaning it is not possible to schedule the job
4526 */
4527 if( newlb > lct - duration )
4528 {
4529 /* initialize conflict analysis if conflict analysis is applicable */
4531 {
4532 SCIP_Real relaxedbd;
4533
4534 assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4535
4536 /* it is enough to overshoot the upper bound of the variable by one */
4537 relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4538
4539 /* initialize conflict analysis */
4541
4542 /* added to upper bound (which was overcut be new lower bound) of the variable */
4544
4545 /* analyze the infeasible */
4546 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4547 begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4548
4549 (*initialized) = TRUE;
4550 }
4551
4552 (*cutoff) = TRUE;
4553 }
4554 else if( newlb > (*bestlb) )
4555 {
4556 INFERINFO inferinfo;
4557
4558 assert(newlb > begin);
4559
4560 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4561
4562 /* construct inference information */
4563 (*inferinfos) = inferInfoToInt(inferinfo);
4564 (*bestlb) = newlb;
4565 }
4566
4567 return SCIP_OKAY;
4568}
4569
4570/** try to tighten the upper bound of the given variable */
4571static
4573 SCIP* scip, /**< SCIP data structure */
4574 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4575 int nvars, /**< number of start time variables (activities) */
4576 SCIP_VAR** vars, /**< array of start time variables */
4577 int* durations, /**< array of durations */
4578 int* demands, /**< array of demands */
4579 int capacity, /**< cumulative capacity */
4580 int hmin, /**< left bound of time axis to be considered (including hmin) */
4581 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4582 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4583 int duration, /**< duration of the job */
4584 int demand, /**< demand of the job */
4585 int est, /**< earliest start time of the job */
4586 int lst, /**< latest start time of the flexible part of the job */
4587 int lct, /**< latest completion time of the job */
4588 int begin, /**< begin of the time window under investigation */
4589 int end, /**< end of the time window under investigation */
4590 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4591 int* bestub, /**< pointer to strope the best upper bound change */
4592 int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4593 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4594 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4595 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4596 )
4597{
4598 int newub;
4599
4600 assert(begin >= hmin);
4601 assert(end <= hmax);
4602 assert(est < begin);
4603
4604 /* check if the time-table edge-finding should infer bounds */
4605 if( !conshdlrdata->ttefinfer )
4606 return SCIP_OKAY;
4607
4608 /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4609 if( lst >= end || lct <= begin )
4610 return SCIP_OKAY;
4611
4612 /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4613 * skip since the overload check will do the job
4614 */
4615 if( lst >= begin && lct <= end )
4616 return SCIP_OKAY;
4617
4618 /* check if the available energy in the time window is to small to handle the flexible part of the job */
4619 if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4620 return SCIP_OKAY;
4621
4622 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4623 * present; therefore, we need to add the core;
4624 *
4625 * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4626 * latest start of the (whole) job
4627 */
4628 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4629 assert(energy >= 0);
4630
4631 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4632 *
4633 * @note we can round down the compute duration w.r.t. the available energy
4634 */
4635 assert(demand > 0);
4636 newub = begin - duration + (int) (energy / demand);
4637
4638 /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4639 * bound (earliest start time); meaning it is not possible to schedule the job
4640 */
4641 if( newub < est )
4642 {
4643 /* initialize conflict analysis if conflict analysis is applicable */
4645 {
4646 SCIP_Real relaxedbd;
4647
4648 assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4649
4650 /* it is enough to undershoot the lower bound of the variable by one */
4651 relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4652
4653 /* initialize conflict analysis */
4655
4656 /* added to lower bound (which was undercut be new upper bound) of the variable */
4658
4659 /* analyze the infeasible */
4660 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4661 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4662
4663 (*initialized) = TRUE;
4664 }
4665
4666 (*cutoff) = TRUE;
4667 }
4668 else if( newub < (*bestub) )
4669 {
4670 INFERINFO inferinfo;
4671
4672 assert(newub < begin);
4673
4674 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4675
4676 /* construct inference information */
4677 (*inferinfos) = inferInfoToInt(inferinfo);
4678 (*bestub) = newub;
4679 }
4680
4681 return SCIP_OKAY;
4682}
4683
4684/** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4685static
4687 SCIP* scip, /**< SCIP data structure */
4688 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4689 int nvars, /**< number of start time variables (activities) */
4690 SCIP_VAR** vars, /**< array of start time variables */
4691 int* durations, /**< array of durations */
4692 int* demands, /**< array of demands */
4693 int capacity, /**< cumulative capacity */
4694 int hmin, /**< left bound of time axis to be considered (including hmin) */
4695 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4696 int* newlbs, /**< array to buffer new lower bounds */
4697 int* newubs, /**< array to buffer new upper bounds */
4698 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4699 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4700 int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4701 int* flexenergies, /**< array of flexible energies in the same order as the variables */
4702 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4703 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4704 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4705 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4706 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4707 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4708 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4709 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4710 )
4711{
4712 int coreEnergyAfterEnd;
4713 SCIP_Longint maxavailable;
4714 SCIP_Longint minavailable;
4715 SCIP_Longint totalenergy;
4716 int nests;
4717 int est;
4718 int lct;
4719 int start;
4720 int end;
4721 int v;
4722
4723 est = INT_MAX;
4724 lct = INT_MIN;
4725
4726 /* compute earliest start and latest completion time of all jobs */
4727 for( v = 0; v < nvars; ++v )
4728 {
4729 start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4730 end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4731
4732 est = MIN(est, start);
4733 lct = MAX(lct, end);
4734 }
4735
4736 /* adjust the effective time horizon */
4737 hmin = MAX(hmin, est);
4738 hmax = MIN(hmax, lct);
4739
4740 end = hmax + 1;
4741 coreEnergyAfterEnd = -1;
4742
4743 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4744 minavailable = maxavailable;
4745 totalenergy = computeTotalEnergy(durations, demands, nvars);
4746
4747 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4748 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4749 return SCIP_OKAY;
4750
4751 nests = nvars;
4752
4753 /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4754 * times define the end of the time interval under investigation
4755 */
4756 for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4757 {
4758 int flexenergy;
4759 int minbegin;
4760 int lbenergy;
4761 int lbcand;
4762 int i;
4763
4764 lct = lcts[v];
4765
4766 /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4767 * infinity capacity is available; hence we skip that
4768 */
4769 if( lct > hmax )
4770 continue;
4771
4772 /* if the latest completion time is smaller then hmin we have to stop */
4773 if( lct <= hmin )
4774 {
4775 assert(v == 0 || lcts[v-1] <= lcts[v]);
4776 break;
4777 }
4778
4779 /* if the latest completion time equals to previous end time, we can continue since this particular interval
4780 * induced by end was just analyzed
4781 */
4782 if( lct == end )
4783 continue;
4784
4785 assert(lct < end);
4786
4787 /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4788 * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4789 * free energy; if so it means that in the next iterate the free-energy cannot be negative
4790 */
4791 if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4792 {
4793 SCIP_Longint freeenergy;
4794
4795 assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4796 assert(coreEnergyAfterEnd >= 0);
4797
4798 /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4799 freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4800
4801 if( freeenergy <= minavailable )
4802 {
4803 SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4804 continue;
4805 }
4806 }
4807
4808 SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4809
4810 end = lct;
4811 coreEnergyAfterEnd = coreEnergyAfterLct[v];
4812
4813 flexenergy = 0;
4814 minavailable = maxavailable;
4815 minbegin = hmax;
4816 lbcand = -1;
4817 lbenergy = 0;
4818
4819 /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4820 * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4821 * wider
4822 */
4823 for( i = nests-1; i >= 0; --i )
4824 {
4825 SCIP_VAR* var;
4826 SCIP_Longint freeenergy;
4827 int duration;
4828 int demand;
4829 int begin;
4830 int idx;
4831 int lst;
4832
4833 idx = perm[i];
4834 assert(idx >= 0);
4835 assert(idx < nvars);
4836 assert(!(*cutoff));
4837
4838 /* the earliest start time of the job */
4839 est = ests[i];
4840
4841 /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4842 * latest completion times (which define end) are scant in non-increasing order
4843 */
4844 if( end <= est )
4845 {
4846 nests--;
4847 continue;
4848 }
4849
4850 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4851 * current ending time
4852 */
4853 if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4854 break;
4855
4856 var = vars[idx];
4857 assert(var != NULL);
4858
4859 duration = durations[idx];
4860 assert(duration > 0);
4861
4862 demand = demands[idx];
4863 assert(demand > 0);
4864
4865 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4866
4867 /* the latest start time of the free part of the job */
4868 lst = lsts[idx];
4869
4870 /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4871 * investigation; hence the overload check will do the the job
4872 */
4873 assert(est <= minbegin);
4874 if( minavailable < maxavailable && est < minbegin )
4875 {
4876 assert(!(*cutoff));
4877
4878 /* try to tighten the upper bound */
4879 SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4880 var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4881 initialized, explanation, cutoff) );
4882
4883 if( *cutoff )
4884 break;
4885 }
4886
4887 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4888 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4889
4890 begin = est;
4891 assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4892
4893 /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4894 * free energy
4895 */
4896 if( begin < hmin )
4897 break;
4898
4899 /* compute the contribution to the flexible energy */
4900 if( lct <= end )
4901 {
4902 /* if the jobs has to finish before the end, all the energy has to be scheduled */
4903 assert(lst >= begin);
4904 assert(flexenergies[idx] >= 0);
4905 flexenergy += flexenergies[idx];
4906 }
4907 else
4908 {
4909 /* the job partly overlaps with the end */
4910 int candenergy;
4911 int energy;
4912
4913 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4914 * w.r.t. latest start time
4915 *
4916 * @note we need to be aware of the effective horizon
4917 */
4918 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4919 assert(end - lst < duration);
4920 assert(energy >= 0);
4921
4922 /* adjust the flexible energy of the time interval */
4923 flexenergy += energy;
4924
4925 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4926 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4927 assert(candenergy >= 0);
4928
4929 /* check if we found a better candidate */
4930 if( candenergy > lbenergy )
4931 {
4932 lbenergy = candenergy;
4933 lbcand = idx;
4934 }
4935 }
4936
4937 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4938 assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4939
4940 /* compute the energy which is not used yet */
4941 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4942
4943 /* check overload */
4944 if( freeenergy < 0 )
4945 {
4946 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4947
4948 /* initialize conflict analysis if conflict analysis is applicable */
4950 {
4951 /* analyze infeasibilty */
4953
4954 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4956 conshdlrdata->usebdwidening, explanation) );
4957
4958 (*initialized) = TRUE;
4959 }
4960
4961 (*cutoff) = TRUE;
4962
4963 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4965
4966 break;
4967 }
4968
4969 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4970 if( lbenergy > 0 && freeenergy < lbenergy )
4971 {
4972 SCIP_Longint energy;
4973 int newlb;
4974 int ect;
4975
4976 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4977 lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4978
4979 /* remove the energy of our job from the ... */
4980 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4981
4982 newlb = end - (int)(energy / demands[lbcand]);
4983
4984 if( newlb > lst )
4985 {
4986 /* initialize conflict analysis if conflict analysis is applicable */
4988 {
4989 SCIP_Real relaxedbd;
4990
4991 /* analyze infeasibilty */
4993
4994 relaxedbd = lst + 1.0;
4995
4996 /* added to upper bound (which was overcut be new lower bound) of the variable */
4997 SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4998
4999 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5000 begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
5001 conshdlrdata->usebdwidening, explanation) );
5002
5003 (*initialized) = TRUE;
5004 }
5005
5006 (*cutoff) = TRUE;
5007 break;
5008 }
5009 else if( newlb > newlbs[lbcand] )
5010 {
5011 INFERINFO inferinfo;
5012
5013 /* construct inference information */
5014 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5015
5016 /* buffer upper bound change */
5017 lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
5018 newlbs[lbcand] = newlb;
5019 }
5020 }
5021
5022 /* check if the current interval has a smaller free energy */
5023 if( minavailable > freeenergy )
5024 {
5025 minavailable = freeenergy;
5026 minbegin = begin;
5027 }
5028 assert(minavailable >= 0);
5029 }
5030 }
5031
5032 return SCIP_OKAY;
5033}
5034
5035/** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
5036static
5038 SCIP* scip, /**< SCIP data structure */
5039 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5040 int nvars, /**< number of start time variables (activities) */
5041 SCIP_VAR** vars, /**< array of start time variables */
5042 int* durations, /**< array of durations */
5043 int* demands, /**< array of demands */
5044 int capacity, /**< cumulative capacity */
5045 int hmin, /**< left bound of time axis to be considered (including hmin) */
5046 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5047 int* newlbs, /**< array to buffer new lower bounds */
5048 int* newubs, /**< array to buffer new upper bounds */
5049 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5050 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5051 int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5052 int* flexenergies, /**< array of flexible energies in the same order as the variables */
5053 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5054 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5055 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5056 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5057 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5058 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5059 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5060 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5061 )
5062{
5063 int coreEnergyAfterStart;
5064 SCIP_Longint maxavailable;
5065 SCIP_Longint minavailable;
5066 SCIP_Longint totalenergy;
5067 int nlcts;
5068 int begin;
5069 int minest;
5070 int maxlct;
5071 int start;
5072 int end;
5073 int v;
5074
5075 if( *cutoff )
5076 return SCIP_OKAY;
5077
5078 begin = hmin - 1;
5079
5080 minest = INT_MAX;
5081 maxlct = INT_MIN;
5082
5083 /* compute earliest start and latest completion time of all jobs */
5084 for( v = 0; v < nvars; ++v )
5085 {
5086 start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5087 end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5088
5089 minest = MIN(minest, start);
5090 maxlct = MAX(maxlct, end);
5091 }
5092
5093 /* adjust the effective time horizon */
5094 hmin = MAX(hmin, minest);
5095 hmax = MIN(hmax, maxlct);
5096
5097 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5098 totalenergy = computeTotalEnergy(durations, demands, nvars);
5099
5100 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5101 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5102 return SCIP_OKAY;
5103
5104 nlcts = 0;
5105
5106 /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5107 * define the start of the time interval under investigation
5108 */
5109 for( v = 0; v < nvars; ++v )
5110 {
5111 int flexenergy;
5112 int minend;
5113 int ubenergy;
5114 int ubcand;
5115 int est;
5116 int i;
5117
5118 est = ests[v];
5119
5120 /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5121 * infinity capacity is available; hence we skip that
5122 */
5123 if( est < hmin )
5124 continue;
5125
5126 /* if the earliest start time is larger or equal then hmax we have to stop */
5127 if( est >= hmax )
5128 break;
5129
5130 /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5131 * induced by start was just analyzed
5132 */
5133 if( est == begin )
5134 continue;
5135
5136 assert(est > begin);
5137
5138 SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5139
5140 begin = est;
5141 coreEnergyAfterStart = coreEnergyAfterEst[v];
5142
5143 flexenergy = 0;
5144 minavailable = maxavailable;
5145 minend = hmin;
5146 ubcand = -1;
5147 ubenergy = 0;
5148
5149 /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5150 * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5151 */
5152 for( i = nlcts; i < nvars; ++i )
5153 {
5154 SCIP_VAR* var;
5155 SCIP_Longint freeenergy;
5156 int duration;
5157 int demand;
5158 int idx;
5159 int lct;
5160 int ect;
5161
5162 idx = perm[i];
5163 assert(idx >= 0);
5164 assert(idx < nvars);
5165 assert(!(*cutoff));
5166
5167 /* the earliest start time of the job */
5168 lct = lcts[i];
5169
5170 /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5171 * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5172 */
5173 if( lct <= begin )
5174 {
5175 nlcts++;
5176 continue;
5177 }
5178
5179 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5180 * start with current beginning time
5181 */
5182 if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5183 break;
5184
5185 var = vars[idx];
5186 assert(var != NULL);
5187
5188 duration = durations[idx];
5189 assert(duration > 0);
5190
5191 demand = demands[idx];
5192 assert(demand > 0);
5193
5195
5196 /* the earliest completion time of the flexible part of the job */
5197 ect = ects[idx];
5198
5199 /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5200 * investigation; hence the overload check will do the the job
5201 */
5202 assert(lct >= minend);
5203 if( minavailable < maxavailable && lct > minend )
5204 {
5205 assert(!(*cutoff));
5206
5207 /* try to tighten the upper bound */
5208 SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5209 var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5210 initialized, explanation, cutoff) );
5211
5212 if( *cutoff )
5213 return SCIP_OKAY;
5214 }
5215
5216 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5217 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5218
5219 end = lct;
5220 assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5221
5222 /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5223 * free energy
5224 */
5225 if( end > hmax )
5226 break;
5227
5228 /* compute the contribution to the flexible energy */
5229 if( est >= begin )
5230 {
5231 /* if the jobs has to finish before the end, all the energy has to be scheduled */
5232 assert(ect <= end);
5233 assert(flexenergies[idx] >= 0);
5234 flexenergy += flexenergies[idx];
5235 }
5236 else
5237 {
5238 /* the job partly overlaps with the end */
5239 int candenergy;
5240 int energy;
5241
5242 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5243 * w.r.t. latest start time
5244 *
5245 * @note we need to be aware of the effective horizon
5246 */
5247 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5248 assert(ect - begin < duration);
5249 assert(energy >= 0);
5250
5251 /* adjust the flexible energy of the time interval */
5252 flexenergy += energy;
5253
5254 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5255 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5256 assert(candenergy >= 0);
5257
5258 /* check if we found a better candidate */
5259 if( candenergy > ubenergy )
5260 {
5261 ubenergy = candenergy;
5262 ubcand = idx;
5263 }
5264 }
5265
5266 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5267 assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5268
5269 /* compute the energy which is not used yet */
5270 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5271
5272 /* check overload */
5273 if( freeenergy < 0 )
5274 {
5275 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5276
5277 /* initialize conflict analysis if conflict analysis is applicable */
5279 {
5280 /* analyze infeasibilty */
5282
5283 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5285 conshdlrdata->usebdwidening, explanation) );
5286
5287 (*initialized) = TRUE;
5288 }
5289
5290 (*cutoff) = TRUE;
5291
5292 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5294
5295 return SCIP_OKAY;
5296 }
5297
5298 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5299 if( ubenergy > 0 && freeenergy < ubenergy )
5300 {
5301 SCIP_Longint energy;
5302 int newub;
5303 int lst;
5304
5305 duration = durations[ubcand];
5306 assert(duration > 0);
5307
5308 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5309 lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5310
5311 /* remove the energy of our job from the ... */
5312 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5313
5314 newub = begin - duration + (int)(energy / demands[ubcand]);
5315
5316 if( newub < ect - duration )
5317 {
5318 /* initialize conflict analysis if conflict analysis is applicable */
5320 {
5321 SCIP_Real relaxedbd;
5322 /* analyze infeasibilty */
5324
5325 relaxedbd = ect - duration - 1.0;
5326
5327 /* added to lower bound (which was undercut be new upper bound) of the variable */
5328 SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5329
5330 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5331 begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5332 conshdlrdata->usebdwidening, explanation) );
5333
5334 (*initialized) = TRUE;
5335 }
5336
5337 (*cutoff) = TRUE;
5338 return SCIP_OKAY;
5339 }
5340 else if( newub < newubs[ubcand] )
5341 {
5342 INFERINFO inferinfo;
5343
5344 /* construct inference information */
5345 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5346
5347 /* buffer upper bound change */
5348 ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5349 newubs[ubcand] = newub;
5350 }
5351 }
5352
5353 /* check if the current interval has a smaller free energy */
5354 if( minavailable > freeenergy )
5355 {
5356 minavailable = freeenergy;
5357 minend = end;
5358 }
5359 assert(minavailable >= 0);
5360 }
5361 }
5362
5363 return SCIP_OKAY;
5364}
5365
5366/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5367 * edge-finding
5368 *
5369 * @note The algorithm is based on the following two papers:
5370 * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5371 * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5372 * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5373 * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5374 * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5375 */
5376static
5378 SCIP* scip, /**< SCIP data structure */
5379 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5380 SCIP_PROFILE* profile, /**< current core profile */
5381 int nvars, /**< number of start time variables (activities) */
5382 SCIP_VAR** vars, /**< array of start time variables */
5383 int* durations, /**< array of durations */
5384 int* demands, /**< array of demands */
5385 int capacity, /**< cumulative capacity */
5386 int hmin, /**< left bound of time axis to be considered (including hmin) */
5387 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5388 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5389 int* nchgbds, /**< pointer to store the number of bound changes */
5390 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5391 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5392 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5393 )
5394{
5395 int* coreEnergyAfterEst;
5396 int* coreEnergyAfterLct;
5397 int* flexenergies;
5398 int* permests;
5399 int* permlcts;
5400 int* lcts;
5401 int* ests;
5402 int* ects;
5403 int* lsts;
5404
5405 int* newlbs;
5406 int* newubs;
5407 int* lbinferinfos;
5408 int* ubinferinfos;
5409
5410 int v;
5411
5412 /* check if a cutoff was already detected */
5413 if( (*cutoff) )
5414 return SCIP_OKAY;
5415
5416 /* check if at least the basic overload checking should be perfomed */
5417 if( !conshdlrdata->ttefcheck )
5418 return SCIP_OKAY;
5419
5420 SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5421
5422 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5423 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5424 SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5425 SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5426 SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5427 SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5428 SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5429 SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5430 SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5431
5432 SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5433 SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5434 SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5435 SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5436
5437 /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5438 for( v = 0; v < nvars; ++v )
5439 {
5440 newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5441 newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5442 lbinferinfos[v] = 0;
5443 ubinferinfos[v] = 0;
5444 }
5445
5446 /* collect earliest start times, latest completion time, and free energy contributions */
5447 collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5448
5449 /* sort the earliest start times and latest completion in non-decreasing order */
5450 SCIPsortIntInt(ests, permests, nvars);
5451 SCIPsortIntInt(lcts, permlcts, nvars);
5452
5453 /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5454 * points
5455 */
5456 computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5457
5458 /* propagate the upper bounds and "opportunistically" the lower bounds */
5459 SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5460 newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5461 permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5462
5463 /* propagate the lower bounds and "opportunistically" the upper bounds */
5464 SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5465 newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5466 permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5467
5468 /* apply the buffer bound changes */
5469 for( v = 0; v < nvars && !(*cutoff); ++v )
5470 {
5471 SCIP_Bool infeasible;
5472 SCIP_Bool tightened;
5473
5474 if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5475 {
5476 SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5477 TRUE, &infeasible, &tightened) );
5478 }
5479 else
5480 {
5481 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5482 }
5483
5484 /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5485 assert(!infeasible);
5486
5487 if( tightened )
5488 {
5489 (*nchgbds)++;
5490
5491 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5493 }
5494
5495 if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5496 {
5497 SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5498 TRUE, &infeasible, &tightened) );
5499 }
5500 else
5501 {
5502 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5503 }
5504
5505 /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5506 * bound update can be infeasible
5507 */
5508 if( infeasible )
5509 {
5510 /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5511 * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5512 * be analyzed in the case when begin and end exceed the 15 bit limit
5513 */
5515 {
5516 INFERINFO inferinfo;
5517 SCIP_VAR* var;
5518 int begin;
5519 int end;
5520
5521 var = vars[v];
5522 assert(var != NULL);
5523
5524 /* initialize conflict analysis */
5526
5527 /* convert int to inference information */
5528 inferinfo = intToInferInfo(ubinferinfos[v]);
5529
5530 /* collect time window from inference information */
5531 begin = inferInfoGetData1(inferinfo);
5532 end = inferInfoGetData2(inferinfo);
5533 assert(begin < end);
5534
5535 /* added to lower bound (which was undercut be new upper bound) of the variable */
5537
5538 /* analysis the upper bound change */
5539 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5540 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5541 conshdlrdata->usebdwidening, explanation) );
5542
5543 (*initialized) = TRUE;
5544 }
5545
5546 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5548
5549 (*cutoff) = TRUE;
5550 break;
5551 }
5552
5553 if( tightened )
5554 {
5555 (*nchgbds)++;
5556
5557 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5559 }
5560 }
5561
5562 SCIPfreeBufferArray(scip, &ubinferinfos);
5563 SCIPfreeBufferArray(scip, &lbinferinfos);
5564 SCIPfreeBufferArray(scip, &newubs);
5565 SCIPfreeBufferArray(scip, &newlbs);
5566
5567 /* free buffer arrays */
5568 SCIPfreeBufferArray(scip, &lsts);
5569 SCIPfreeBufferArray(scip, &ects);
5570 SCIPfreeBufferArray(scip, &ests);
5571 SCIPfreeBufferArray(scip, &lcts);
5572 SCIPfreeBufferArray(scip, &permests);
5573 SCIPfreeBufferArray(scip, &permlcts);
5574 SCIPfreeBufferArray(scip, &flexenergies);
5575 SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5576 SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5577
5578 return SCIP_OKAY;
5579}
5580
5581/** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5582 * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5583 * time table propagator
5584 */
5585static
5587 SCIP* scip, /**< SCIP data structure */
5588 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5589 SCIP_PROFILE* profile, /**< core profile */
5590 int nvars, /**< number of start time variables (activities) */
5591 SCIP_VAR** vars, /**< array of start time variables */
5592 int* durations, /**< array of durations */
5593 int* demands, /**< array of demands */
5594 int capacity, /**< cumulative capacity */
5595 int hmin, /**< left bound of time axis to be considered (including hmin) */
5596 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5597 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5598 int* nchgbds, /**< pointer to store the number of bound changes */
5599 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5600 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5601 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5602 )
5603{
5604 SCIP_Bool infeasible;
5605 int v;
5606
5607 assert(scip != NULL);
5608 assert(nvars > 0);
5609 assert(cons != NULL);
5610 assert(cutoff != NULL);
5611
5612 /* check if already a cutoff was detected */
5613 if( (*cutoff) )
5614 return SCIP_OKAY;
5615
5616 /* check if the time tabling should infer bounds */
5617 if( !conshdlrdata->ttinfer )
5618 return SCIP_OKAY;
5619
5620 assert(*initialized == FALSE);
5621
5622 SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5623 SCIPconsGetName(cons), hmin, hmax, capacity);
5624
5625 infeasible = FALSE;
5626
5627 /* if core profile is empty; nothing to do */
5628 if( SCIPprofileGetNTimepoints(profile) <= 1 )
5629 return SCIP_OKAY;
5630
5631 /* start checking each job whether the bounds can be improved */
5632 for( v = 0; v < nvars; ++v )
5633 {
5634 SCIP_VAR* var;
5635 int demand;
5636 int duration;
5637 int begin;
5638 int end;
5639 int est;
5640 int lst;
5641
5642 var = vars[v];
5643 assert(var != NULL);
5644
5645 duration = durations[v];
5646 assert(duration > 0);
5647
5648 /* collect earliest and latest start time */
5651
5652 /* check if the start time variables is already fixed; in that case we can ignore the job */
5653 if( est == lst )
5654 continue;
5655
5656 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5657 if( lst + duration <= hmin || est >= hmax )
5658 continue;
5659
5660 /* compute core interval w.r.t. effective time horizon */
5661 begin = MAX(hmin, lst);
5662 end = MIN(hmax, est + duration);
5663
5664 demand = demands[v];
5665 assert(demand > 0);
5666
5667 /* if the job has a core, remove it first */
5668 if( begin < end )
5669 {
5670 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5671 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5672
5673 SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5674 }
5675
5676 /* first try to update the earliest start time */
5677 SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5678 profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5679
5680 if( *cutoff )
5681 break;
5682
5683 /* second try to update the latest start time */
5684 SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5685 profile, v, nchgbds) );
5686
5687 if( *cutoff )
5688 break;
5689
5690 /* collect the potentially updated earliest and latest start time */
5693
5694 /* compute core interval w.r.t. effective time horizon */
5695 begin = MAX(hmin, lst);
5696 end = MIN(hmax, est + duration);
5697
5698 /* after updating the bound we might have a new core */
5699 if( begin < end )
5700 {
5701 int pos;
5702
5703 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5704 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5705
5706 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5707
5708 if( infeasible )
5709 {
5710 /* use conflict analysis to analysis the core insertion which was infeasible */
5711 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5712 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5713
5714 if( explanation != NULL )
5715 explanation[v] = TRUE;
5716
5717 (*cutoff) = TRUE;
5718
5719 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5721
5722 break;
5723 }
5724 }
5725 }
5726
5727 return SCIP_OKAY;
5728}
5729
5730
5731/** node data structure for the binary tree used for edgefinding (with overload checking) */
5732struct SCIP_NodeData
5733{
5734 SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5735 SCIP_Real key; /**< key which is to insert the corresponding search node */
5736 int est; /**< earliest start time if the node data belongs to a leaf */
5737 int lct; /**< latest completion time if the node data belongs to a leaf */
5738 int demand; /**< demand of the job if the node data belongs to a leaf */
5739 int duration; /**< duration of the job if the node data belongs to a leaf */
5740 int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5741 int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5742 SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5743 int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5744 int energylambda;
5745 SCIP_Longint enveloplambda;
5746 int idx; /**< index of the start time variable in the (global) variable array */
5747 SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5748};
5749typedef struct SCIP_NodeData SCIP_NODEDATA;
5750
5751
5752/** update node data structure starting from the given node along the path to the root node */
5753static
5755 SCIP* scip, /**< SCIP data structure */
5756 SCIP_BTNODE* node /**< search node which inserted */
5757 )
5758{
5759 SCIP_BTNODE* left;
5760 SCIP_BTNODE* right;
5762 SCIP_NODEDATA* leftdata;
5763 SCIP_NODEDATA* rightdata;
5764
5765 SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5766
5767 if( SCIPbtnodeIsLeaf(node) )
5768 node = SCIPbtnodeGetParent(node);
5769
5770 while( node != NULL )
5771 {
5772 /* get node data */
5774 assert(nodedata != NULL);
5775
5776 /* collect node data from left node */
5777 left = SCIPbtnodeGetLeftchild(node);
5778 assert(left != NULL);
5779 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5780 assert(leftdata != NULL);
5781
5782 /* collect node data from right node */
5783 right = SCIPbtnodeGetRightchild(node);
5784 assert(right != NULL);
5785 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5786 assert(rightdata != NULL);
5787
5788 /* update envelop and energy */
5789 if( leftdata->enveloptheta >= 0 )
5790 {
5791 assert(rightdata->energytheta != -1);
5792 nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5793 }
5794 else
5795 nodedata->enveloptheta = rightdata->enveloptheta;
5796
5797 assert(leftdata->energytheta != -1);
5798 assert(rightdata->energytheta != -1);
5799 nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5800
5801 if( leftdata->enveloplambda >= 0 )
5802 {
5803 assert(rightdata->energytheta != -1);
5804 nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5805 }
5806 else
5807 nodedata->enveloplambda = rightdata->enveloplambda;
5808
5809 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5810 nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5811
5812 SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5813
5814 if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5815 {
5816 assert(rightdata->energytheta != -1);
5817 assert(leftdata->energytheta != -1);
5818 nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5819 }
5820 else if( rightdata->energylambda >= 0 )
5821 {
5822 assert(leftdata->energytheta != -1);
5823 nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5824 }
5825 else if( leftdata->energylambda >= 0 )
5826 {
5827 assert(rightdata->energytheta != -1);
5828 nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5829 }
5830 else
5831 nodedata->energylambda = -1;
5832
5833 /* go to parent */
5834 node = SCIPbtnodeGetParent(node);
5835 }
5836
5837 SCIPdebugMsg(scip, "updating done\n");
5838}
5839
5840/** updates the key of the first parent on the trace which comes from left */
5841static
5843 SCIP_BTNODE* node, /**< node to start the trace */
5844 SCIP_Real key /**< update search key */
5845 )
5846{
5847 assert(node != NULL);
5848
5849 while( !SCIPbtnodeIsRoot(node) )
5850 {
5851 SCIP_BTNODE* parent;
5852
5853 parent = SCIPbtnodeGetParent(node);
5854 assert(parent != NULL);
5855
5856 if( SCIPbtnodeIsLeftchild(node) )
5857 {
5859
5861 assert(nodedata != NULL);
5862
5863 nodedata->key = key;
5864 return;
5865 }
5866
5867 node = parent;
5868 }
5869}
5870
5871
5872/** deletes the given node and updates all envelops */
5873static
5875 SCIP* scip, /**< SCIP data structure */
5876 SCIP_BT* tree, /**< binary tree */
5877 SCIP_BTNODE* node /**< node to be deleted */
5878 )
5879{
5880 SCIP_BTNODE* parent;
5881 SCIP_BTNODE* grandparent;
5882 SCIP_BTNODE* sibling;
5883
5884 assert(scip != NULL);
5885 assert(tree != NULL);
5886 assert(node != NULL);
5887
5888 assert(SCIPbtnodeIsLeaf(node));
5889 assert(!SCIPbtnodeIsRoot(node));
5890
5891 SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5892
5893 parent = SCIPbtnodeGetParent(node);
5894 assert(parent != NULL);
5895 if( SCIPbtnodeIsLeftchild(node) )
5896 {
5897 sibling = SCIPbtnodeGetRightchild(parent);
5899 }
5900 else
5901 {
5902 sibling = SCIPbtnodeGetLeftchild(parent);
5904 }
5905 assert(sibling != NULL);
5906
5907 grandparent = SCIPbtnodeGetParent(parent);
5908
5909 if( grandparent != NULL )
5910 {
5911 /* reset parent of sibling */
5912 SCIPbtnodeSetParent(sibling, grandparent);
5913
5914 /* reset child of grandparent to sibling */
5915 if( SCIPbtnodeIsLeftchild(parent) )
5916 {
5917 SCIPbtnodeSetLeftchild(grandparent, sibling);
5918 }
5919 else
5920 {
5922
5923 assert(SCIPbtnodeIsRightchild(parent));
5924 SCIPbtnodeSetRightchild(grandparent, sibling);
5925
5927
5928 updateKeyOnTrace(grandparent, nodedata->key);
5929 }
5930
5931 updateEnvelope(scip, grandparent);
5932 }
5933 else
5934 {
5935 SCIPbtnodeSetParent(sibling, NULL);
5936
5937 SCIPbtSetRoot(tree, sibling);
5938 }
5939
5940 SCIPbtnodeFree(tree, &parent);
5941
5942 return SCIP_OKAY;
5943}
5944
5945/** moves a node form the theta set into the lambda set and updates the envelops */
5946static
5948 SCIP* scip, /**< SCIP data structure */
5949 SCIP_BT* tree, /**< binary tree */
5950 SCIP_BTNODE* node /**< node to move into the lambda set */
5951 )
5952{
5954
5955 assert(scip != NULL);
5956 assert(tree != NULL);
5957 assert(node != NULL);
5958
5960 assert(nodedata != NULL);
5961 assert(nodedata->intheta);
5962
5963 /* move the contributions form the theta set into the lambda set */
5964 assert(nodedata->enveloptheta != -1);
5965 assert(nodedata->energytheta != -1);
5966 assert(nodedata->enveloplambda == -1);
5967 assert(nodedata->energylambda == -1);
5968 nodedata->enveloplambda = nodedata->enveloptheta;
5969 nodedata->energylambda = nodedata->energytheta;
5970
5971 nodedata->enveloptheta = -1;
5972 nodedata->energytheta = 0;
5973 nodedata->intheta = FALSE;
5974
5975 /* update the energy and envelop values on trace */
5976 updateEnvelope(scip, node);
5977
5978 return SCIP_OKAY;
5979}
5980
5981/** inserts a node into the theta set and update the envelops */
5982static
5984 SCIP* scip, /**< SCIP data structure */
5985 SCIP_BT* tree, /**< binary tree */
5986 SCIP_BTNODE* node, /**< node to insert */
5987 SCIP_NODEDATA* nodedatas, /**< array of node data */
5988 int* nodedataidx, /**< array of indices for node data */
5989 int* nnodedatas /**< pointer to number of node data */
5990 )
5991{
5992 /* if the tree is empty the node will be the root node */
5993 if( SCIPbtIsEmpty(tree) )
5994 {
5995 SCIPbtSetRoot(tree, node);
5996 }
5997 else
5998 {
5999 SCIP_NODEDATA* newnodedata;
6000 SCIP_NODEDATA* leafdata;
6002 SCIP_BTNODE* leaf;
6003 SCIP_BTNODE* newnode;
6004 SCIP_BTNODE* parent;
6005
6006 leaf = SCIPbtGetRoot(tree);
6007 assert(leaf != NULL);
6008
6009 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6010 assert(leafdata != NULL);
6011
6013 assert(nodedata != NULL);
6014 assert(nodedata->intheta);
6015
6016 /* find the position to insert the node */
6017 while( !SCIPbtnodeIsLeaf(leaf) )
6018 {
6019 if( nodedata->key < leafdata->key )
6020 leaf = SCIPbtnodeGetLeftchild(leaf);
6021 else
6022 leaf = SCIPbtnodeGetRightchild(leaf);
6023
6024 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6025 assert(leafdata != NULL);
6026 }
6027
6028 assert(leaf != NULL);
6029 assert(leaf != node);
6030
6031 /* store node data to be able to delete them latter */
6032 newnodedata = &nodedatas[*nnodedatas];
6033 nodedataidx[*nnodedatas] = *nnodedatas;
6034 ++(*nnodedatas);
6035
6036 /* init node data */
6037 newnodedata->var = NULL;
6038 newnodedata->key = SCIP_INVALID;
6039 newnodedata->est = INT_MIN;
6040 newnodedata->lct = INT_MAX;
6041 newnodedata->duration = 0;
6042 newnodedata->demand = 0;
6043 newnodedata->enveloptheta = -1;
6044 newnodedata->energytheta = 0;
6045 newnodedata->enveloplambda = -1;
6046 newnodedata->energylambda = -1;
6047 newnodedata->idx = -1;
6048 newnodedata->intheta = TRUE;
6049
6050 /* create a new node */
6051 SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6052 assert(newnode != NULL);
6053
6054 parent = SCIPbtnodeGetParent(leaf);
6055
6056 if( parent != NULL )
6057 {
6058 SCIPbtnodeSetParent(newnode, parent);
6059
6060 /* check if the node is the left child */
6061 if( SCIPbtnodeGetLeftchild(parent) == leaf )
6062 {
6063 SCIPbtnodeSetLeftchild(parent, newnode);
6064 }
6065 else
6066 {
6067 SCIPbtnodeSetRightchild(parent, newnode);
6068 }
6069 }
6070 else
6071 SCIPbtSetRoot(tree, newnode);
6072
6073 if( nodedata->key < leafdata->key )
6074 {
6075 /* node is on the left */
6076 SCIPbtnodeSetLeftchild(newnode, node);
6077 SCIPbtnodeSetRightchild(newnode, leaf);
6078 newnodedata->key = nodedata->key;
6079 }
6080 else
6081 {
6082 /* leaf is on the left */
6083 SCIPbtnodeSetLeftchild(newnode, leaf);
6084 SCIPbtnodeSetRightchild(newnode, node);
6085 newnodedata->key = leafdata->key;
6086 }
6087
6088 SCIPbtnodeSetParent(leaf, newnode);
6089 SCIPbtnodeSetParent(node, newnode);
6090 }
6091
6092 /* update envelop */
6093 updateEnvelope(scip, node);
6094
6095 return SCIP_OKAY;
6096}
6097
6098/** returns the leaf responsible for the lambda energy */
6099static
6101 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6102 )
6103{
6104 SCIP_BTNODE* left;
6105 SCIP_BTNODE* right;
6107 SCIP_NODEDATA* leftdata;
6108 SCIP_NODEDATA* rightdata;
6109
6110 assert(node != NULL);
6111
6113 assert(nodedata != NULL);
6114
6115 /* check if the node is the (responsible) leaf */
6116 if( SCIPbtnodeIsLeaf(node) )
6117 {
6118 assert(!nodedata->intheta);
6119 return node;
6120 }
6121
6122 left = SCIPbtnodeGetLeftchild(node);
6123 assert(left != NULL);
6124
6125 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6126 assert(leftdata != NULL);
6127
6128 right = SCIPbtnodeGetRightchild(node);
6129 assert(right != NULL);
6130
6131 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6132 assert(rightdata != NULL);
6133
6134 assert(nodedata->energylambda != -1);
6135 assert(rightdata->energytheta != -1);
6136
6137 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6139
6140 assert(leftdata->energytheta != -1);
6141 assert(rightdata->energylambda != -1);
6142 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6143
6145}
6146
6147/** returns the leaf responsible for the lambda envelop */
6148static
6150 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6151 )
6152{
6153 SCIP_BTNODE* left;
6154 SCIP_BTNODE* right;
6156 SCIP_NODEDATA* leftdata;
6157 SCIP_NODEDATA* rightdata;
6158
6159 assert(node != NULL);
6160
6162 assert(nodedata != NULL);
6163
6164 /* check if the node is the (responsible) leaf */
6165 if( SCIPbtnodeIsLeaf(node) )
6166 {
6167 assert(!nodedata->intheta);
6168 return node;
6169 }
6170
6171 left = SCIPbtnodeGetLeftchild(node);
6172 assert(left != NULL);
6173
6174 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6175 assert(leftdata != NULL);
6176
6177 right = SCIPbtnodeGetRightchild(node);
6178 assert(right != NULL);
6179
6180 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6181 assert(rightdata != NULL);
6182
6183 assert(nodedata->enveloplambda != -1);
6184 assert(rightdata->energytheta != -1);
6185
6186 /* check if the left or right child is the one defining the envelop for the lambda set */
6187 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6189 else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6190 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6192
6193 assert(rightdata->enveloplambda != -1);
6194 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6195
6197}
6198
6199
6200/** reports all elements from set theta to generate a conflicting set */
6201static
6203 SCIP_BTNODE* node, /**< node within a theta subtree */
6204 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6205 int* nelements, /**< pointer to store the number of elements in omegaset */
6206 int* est, /**< pointer to store the earliest start time of the omega set */
6207 int* lct, /**< pointer to store the latest start time of the omega set */
6208 int* energy /**< pointer to store the energy of the omega set */
6209 )
6210{
6212
6214 assert(nodedata != NULL);
6215
6216 if( !SCIPbtnodeIsLeaf(node) )
6217 {
6218 collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6219 collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6220 }
6221 else if( nodedata->intheta )
6222 {
6223 assert(nodedata->var != NULL);
6224 SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6225
6226 omegaset[*nelements] = node;
6227 (*est) = MIN(*est, nodedata->est);
6228 (*lct) = MAX(*lct, nodedata->lct);
6229 (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6230 (*nelements)++;
6231 }
6232}
6233
6234
6235/** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6236static
6238 SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6239 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6240 int* nelements, /**< pointer to store the number of elements in omegaset */
6241 int* est, /**< pointer to store the earliest start time of the omega set */
6242 int* lct, /**< pointer to store the latest start time of the omega set */
6243 int* energy /**< pointer to store the energy of the omega set */
6244 )
6245{
6246 assert(node != NULL);
6247
6248 if( SCIPbtnodeIsLeaf(node) )
6249 {
6250 collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6251 }
6252 else
6253 {
6254 SCIP_BTNODE* left;
6255 SCIP_BTNODE* right;
6257 SCIP_NODEDATA* leftdata;
6258 SCIP_NODEDATA* rightdata;
6259
6261 assert(nodedata != NULL);
6262
6263 left = SCIPbtnodeGetLeftchild(node);
6264 assert(left != NULL);
6265
6266 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6267 assert(leftdata != NULL);
6268
6269 right = SCIPbtnodeGetRightchild(node);
6270 assert(right != NULL);
6271
6272 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6273 assert(rightdata != NULL);
6274
6276 assert(nodedata != NULL);
6277
6278 assert(nodedata->enveloptheta != -1);
6279 assert(rightdata->energytheta != -1);
6280
6281 if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6282 {
6283 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6284 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6285 }
6286 else
6287 {
6288 assert(rightdata->enveloptheta != -1);
6289 assert(nodedata->enveloptheta == rightdata->enveloptheta);
6290 traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6291 }
6292 }
6293}
6294
6295/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6296static
6298 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6299 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6300 int* nelements, /**< pointer to store the number of elements in omega set */
6301 int* est, /**< pointer to store the earliest start time of the omega set */
6302 int* lct, /**< pointer to store the latest start time of the omega set */
6303 int* energy /**< pointer to store the energy of the omega set */
6304 )
6305{
6306 SCIP_BTNODE* left;
6307 SCIP_BTNODE* right;
6309 SCIP_NODEDATA* leftdata;
6310 SCIP_NODEDATA* rightdata;
6311
6312 assert(node != NULL);
6313
6315 assert(nodedata != NULL);
6316
6317 /* check if the node is a leaf */
6318 if( SCIPbtnodeIsLeaf(node) )
6319 return;
6320
6321 left = SCIPbtnodeGetLeftchild(node);
6322 assert(left != NULL);
6323
6324 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6325 assert(leftdata != NULL);
6326
6327 right = SCIPbtnodeGetRightchild(node);
6328 assert(right != NULL);
6329
6330 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6331 assert(rightdata != NULL);
6332
6333 assert(nodedata->energylambda != -1);
6334 assert(rightdata->energytheta != -1);
6335
6336 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6337 {
6338 traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6339 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6340 }
6341 else
6342 {
6343 assert(leftdata->energytheta != -1);
6344 assert(rightdata->energylambda != -1);
6345 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6346
6347 collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6348 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6349 }
6350}
6351
6352/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6353static
6355 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6356 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6357 int* nelements, /**< pointer to store the number of elements in omega set */
6358 int* est, /**< pointer to store the earliest start time of the omega set */
6359 int* lct, /**< pointer to store the latest start time of the omega set */
6360 int* energy /**< pointer to store the energy of the omega set */
6361 )
6362{
6363 SCIP_BTNODE* left;
6364 SCIP_BTNODE* right;
6366 SCIP_NODEDATA* leftdata;
6367 SCIP_NODEDATA* rightdata;
6368
6369 assert(node != NULL);
6370
6372 assert(nodedata != NULL);
6373
6374 /* check if the node is a leaf */
6375 if( SCIPbtnodeIsLeaf(node) )
6376 {
6377 assert(!nodedata->intheta);
6378 return;
6379 }
6380
6381 left = SCIPbtnodeGetLeftchild(node);
6382 assert(left != NULL);
6383
6384 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6385 assert(leftdata != NULL);
6386
6387 right = SCIPbtnodeGetRightchild(node);
6388 assert(right != NULL);
6389
6390 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6391 assert(rightdata != NULL);
6392
6393 assert(nodedata->enveloplambda != -1);
6394 assert(rightdata->energytheta != -1);
6395
6396 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6397 {
6398 traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6399 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6400 }
6401 else
6402 {
6403 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6404 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6405 {
6406 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6407 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6408 }
6409 else
6410 {
6411 assert(rightdata->enveloplambda != -1);
6412 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6413 traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6414 }
6415 }
6416}
6417
6418/** compute the energy contribution by job which corresponds to the given leaf */
6419static
6421 SCIP_BTNODE* node /**< leaf */
6422 )
6423{
6425 int duration;
6426
6428 assert(nodedata != NULL);
6429 assert(nodedata->var != NULL);
6430
6431 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6432 assert(duration > 0);
6433
6434 SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6436 SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6437
6438 /* return energy which is contributed by the start time variable */
6439 return nodedata->demand * duration;
6440}
6441
6442/** comparison method for two node data w.r.t. the earliest start time */
6443static
6445{
6446 int est1;
6447 int est2;
6448
6449 est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6450 est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6451
6452 return (est1 - est2);
6453}
6454
6455/** comparison method for two node data w.r.t. the latest completion time */
6456static
6458{
6459 SCIP_NODEDATA* nodedatas;
6460
6461 nodedatas = (SCIP_NODEDATA*) dataptr;
6462 return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6463}
6464
6465
6466/** an overload was detected; initialized conflict analysis, add an initial reason
6467 *
6468 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6469 */
6470static
6472 SCIP* scip, /**< SCIP data structure */
6473 SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6474 int capacity, /**< cumulative capacity */
6475 int nleaves, /**< number of responsible leaves */
6476 int est, /**< earliest start time of the ...... */
6477 int lct, /**< latest completly time of the .... */
6478 int reportedenergy, /**< energy which already reported */
6479 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6480 int shift, /**< shift applied to all jobs before adding them to the tree */
6481 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6482 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6483 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6484 )
6485{
6486 SCIP_Longint energy;
6487 int j;
6488
6489 /* do nothing if conflict analysis is not applicable */
6491 return SCIP_OKAY;
6492
6493 SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6494
6495 /* compute energy of initial time window */
6496 energy = ((SCIP_Longint) lct - est) * capacity;
6497
6498 /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6499 SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6500
6501 /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6502 * thereby, compute the time window of interest
6503 */
6504 for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6505 {
6507
6509 assert(nodedata != NULL);
6510
6511 reportedenergy += computeEnergyContribution(leaves[j]);
6512
6513 /* adjust energy if the earliest start time decrease */
6514 if( nodedata->est < est )
6515 {
6516 est = nodedata->est;
6517 energy = ((SCIP_Longint) lct - est) * capacity;
6518 }
6519 }
6520 assert(reportedenergy > energy);
6521
6522 SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6523
6524 /* initialize conflict analysis */
6526
6527 /* flip earliest start time and latest completion time */
6528 if( !propest )
6529 {
6530 SCIPswapInts(&est, &lct);
6531
6532 /* shift earliest start time and latest completion time */
6533 lct = shift - lct;
6534 est = shift - est;
6535 }
6536 else
6537 {
6538 /* shift earliest start time and latest completion time */
6539 lct = lct + shift;
6540 est = est + shift;
6541 }
6542
6543 nleaves = j;
6544
6545 /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6546 * overloaded
6547 */
6548 for( j = nleaves-1; j >= 0; --j )
6549 {
6551
6553 assert(nodedata != NULL);
6554 assert(nodedata->var != NULL);
6555
6556 /* check if bound widening should be used */
6557 if( usebdwidening )
6558 {
6559 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6560 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6561 }
6562 else
6563 {
6566 }
6567
6568 if( explanation != NULL )
6569 explanation[nodedata->idx] = TRUE;
6570 }
6571
6572 (*initialized) = TRUE;
6573
6574 return SCIP_OKAY;
6575}
6576
6577/** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6578 * responsible interval bounds in *est_omega and *lct_omega
6579 */
6580static
6582 SCIP* scip, /**< SCIP data structure */
6583 int duration, /**< duration of the job to move */
6584 int demand, /**< demand of the job to move */
6585 int capacity, /**< cumulative capacity */
6586 int est, /**< earliest start time of the omega set */
6587 int lct, /**< latest start time of the omega set */
6588 int energy /**< energy of the omega set */
6589 )
6590{
6591 int newest;
6592
6593 newest = 0;
6594
6595 assert(scip != NULL);
6596
6597 if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6598 {
6599 if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6600 {
6601 newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6602 newest += est;
6603 }
6604 }
6605
6606 return newest;
6607}
6608
6609/** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6610 *
6611 * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6612 * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6613 */
6614static
6616 SCIP* scip, /**< SCIP data structure */
6617 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6618 SCIP_CONS* cons, /**< constraint which is propagated */
6619 SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6620 SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6621 int capacity, /**< cumulative capacity */
6622 int ncands, /**< number of candidates */
6623 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6624 int shift, /**< shift applied to all jobs before adding them to the tree */
6625 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6626 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6627 int* nchgbds, /**< pointer to store the number of bound changes */
6628 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6629 )
6630{
6631 SCIP_NODEDATA* rootdata;
6632 int j;
6633
6634 assert(!SCIPbtIsEmpty(tree));
6635
6636 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6637 assert(rootdata != NULL);
6638
6639 /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6640 for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6641 {
6643
6644 if( SCIPbtnodeIsRoot(leaves[j]) )
6645 break;
6646
6648 assert(nodedata->est != -1);
6649
6650 /* check if the root lambda envelop exeeds the available capacity */
6651 while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6652 {
6653 SCIP_BTNODE** omegaset;
6654 SCIP_BTNODE* leaf;
6655 SCIP_NODEDATA* leafdata;
6656 int nelements;
6657 int energy;
6658 int newest;
6659 int est;
6660 int lct;
6661
6662 assert(!(*cutoff));
6663
6664 /* find responsible leaf for the lambda envelope */
6666 assert(leaf != NULL);
6667 assert(SCIPbtnodeIsLeaf(leaf));
6668
6669 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6670 assert(leafdata != NULL);
6671 assert(!leafdata->intheta);
6672 assert(leafdata->duration > 0);
6673 assert(leafdata->est >= 0);
6674
6675 /* check if the job has to be removed since its latest completion is to large */
6676 if( leafdata->est + leafdata->duration >= nodedata->lct )
6677 {
6678 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6679
6680 /* the root might changed therefore we need to collect the new root node data */
6681 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6682 assert(rootdata != NULL);
6683
6684 continue;
6685 }
6686
6687 /* compute omega set */
6688 SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6689
6690 nelements = 0;
6691 est = INT_MAX;
6692 lct = INT_MIN;
6693 energy = 0;
6694
6695 /* collect the omega set from theta set */
6696 traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6697 assert(nelements > 0);
6698 assert(nelements < ncands);
6699
6700 newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6701
6702 /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6703 if( newest > lct )
6704 {
6705 SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6706
6707 /* analyze over load */
6708 SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6709 conshdlrdata->usebdwidening, initialized, explanation) );
6710 (*cutoff) = TRUE;
6711
6712 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6714 }
6715 else if( newest > 0 )
6716 {
6717 SCIP_Bool infeasible;
6718 SCIP_Bool tightened;
6719 INFERINFO inferinfo;
6720
6721 if( propest )
6722 {
6723 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6724 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6725
6726 SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6727 SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6728
6729 if( inferInfoIsValid(inferinfo) )
6730 {
6731 SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6732 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6733 }
6734 else
6735 {
6736 SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6737 TRUE, &infeasible, &tightened) );
6738 }
6739
6740 /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6742 }
6743 else
6744 {
6745 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6746 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6747
6748 SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6749 SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6750
6751 if( inferInfoIsValid(inferinfo) )
6752 {
6753 SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6754 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6755 }
6756 else
6757 {
6758 SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6759 TRUE, &infeasible, &tightened) );
6760 }
6761
6762 /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6764 }
6765
6766 /* adjust the earliest start time */
6767 if( tightened )
6768 {
6769 leafdata->est = newest;
6770 (*nchgbds)++;
6771 }
6772
6773 if( infeasible )
6774 {
6775 /* initialize conflict analysis if conflict analysis is applicable */
6777 {
6778 int i;
6779
6780 SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6781
6783
6784 /* add lower and upper bound of variable which leads to the infeasibilty */
6785 SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6786 SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6787
6788 if( explanation != NULL )
6789 explanation[leafdata->idx] = TRUE;
6790
6791 /* add lower and upper bound of variable which lead to the infeasibilty */
6792 for( i = 0; i < nelements; ++i )
6793 {
6794 nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6795 assert(nodedata != NULL);
6796
6799
6800 if( explanation != NULL )
6801 explanation[nodedata->idx] = TRUE;
6802 }
6803
6804 (*initialized) = TRUE;
6805 }
6806
6807 (*cutoff) = TRUE;
6808
6809 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6811 }
6812 }
6813
6814 /* free omegaset array */
6815 SCIPfreeBufferArray(scip, &omegaset);
6816
6817 /* delete responsible leaf from lambda */
6818 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6819
6820 /* the root might changed therefore we need to collect the new root node data */
6821 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6822 assert(rootdata != NULL);
6823 }
6824
6825 /* move current job j from the theta set into the lambda set */
6826 SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6827 }
6828
6829 return SCIP_OKAY;
6830}
6831
6832/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6833 *
6834 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6835 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6836 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6837 */
6838static
6840 SCIP* scip, /**< SCIP data structure */
6841 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6842 int nvars, /**< number of start time variables (activities) */
6843 SCIP_VAR** vars, /**< array of start time variables */
6844 int* durations, /**< array of durations */
6845 int* demands, /**< array of demands */
6846 int capacity, /**< cumulative capacity */
6847 int hmin, /**< left bound of time axis to be considered (including hmin) */
6848 int hmax, /**< right bound of time axis to be considered (not including hmax) */
6849 SCIP_CONS* cons, /**< constraint which is propagated */
6850 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6851 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6852 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6853 int* nchgbds, /**< pointer to store the number of bound changes */
6854 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6855 )
6856{
6857 SCIP_NODEDATA* nodedatas;
6858 SCIP_BTNODE** leaves;
6859 SCIP_BT* tree;
6860 int* nodedataidx;
6861
6862 int totalenergy;
6863 int nnodedatas;
6864 int ninsertcands;
6865 int ncands;
6866
6867 int shift;
6868 int idx = -1;
6869 int j;
6870
6871 assert(scip != NULL);
6872 assert(cons != NULL);
6873 assert(initialized != NULL);
6874 assert(cutoff != NULL);
6875 assert(*cutoff == FALSE);
6876
6877 SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6878
6879 SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6880 SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6881 SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6882
6883 ncands = 0;
6884 totalenergy = 0;
6885
6887
6888 /* compute the shift which we apply to compute .... latest completion time of all jobs */
6889 if( propest )
6890 shift = 0;
6891 else
6892 {
6893 shift = 0;
6894
6895 /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6896 * earliest start time propagation to handle the latest completion times
6897 */
6898 for( j = 0; j < nvars; ++j )
6899 {
6900 int lct;
6901
6902 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6903 shift = MAX(shift, lct);
6904 }
6905 }
6906
6907 /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6908 * horizon
6909 */
6910 for( j = 0; j < nvars; ++j )
6911 {
6913 SCIP_VAR* var;
6914 int duration;
6915 int leftadjust;
6916 int rightadjust;
6917 int energy;
6918 int est;
6919 int lct;
6920
6921 var = vars[j];
6922 assert(var != NULL);
6923
6924 duration = durations[j];
6925 assert(duration > 0);
6926
6927 leftadjust = 0;
6928 rightadjust = 0;
6929
6931 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6932
6933 /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6934 * effective horizon [hmin,hmax)
6935 */
6936 if( conshdlrdata->useadjustedjobs )
6937 {
6938 if( est < hmin )
6939 {
6940 leftadjust = (hmin - est);
6941 est = hmin;
6942 }
6943 if( lct > hmax )
6944 {
6945 rightadjust = (lct - hmax);
6946 lct = hmax;
6947 }
6948
6949 /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6950 * with the effective time horizon
6951 */
6952 if( duration - leftadjust - rightadjust <= 0 )
6953 continue;
6954 }
6955 else if( est < hmin || lct > hmax )
6956 continue;
6957
6958 energy = demands[j] * (duration - leftadjust - rightadjust);
6959 assert(energy > 0);
6960
6961 totalenergy += energy;
6962
6963 /* flip earliest start time and latest completion time */
6964 if( !propest )
6965 {
6966 SCIPswapInts(&est, &lct);
6967
6968 /* shift earliest start time and latest completion time */
6969 lct = shift - lct;
6970 est = shift - est;
6971 }
6972 else
6973 {
6974 /* shift earliest start time and latest completion time */
6975 lct = lct - shift;
6976 est = est - shift;
6977 }
6978 assert(est < lct);
6979 assert(est >= 0);
6980 assert(lct >= 0);
6981
6982 /* create search node data */
6983 nodedata = &nodedatas[ncands];
6984 nodedataidx[ncands] = ncands;
6985 ++ncands;
6986
6987 /* initialize search node data */
6988 /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6989 nodedata->key = est + j / (2.0 * nvars);
6990 nodedata->var = var;
6991 nodedata->est = est;
6992 nodedata->lct = lct;
6993 nodedata->demand = demands[j];
6994 nodedata->duration = duration;
6995 nodedata->leftadjust = leftadjust;
6996 nodedata->rightadjust = rightadjust;
6997
6998 /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6999 * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
7000 * particular time interval [a,b] against the time interval [0,b].
7001 */
7002 nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
7003 nodedata->energytheta = energy;
7004 nodedata->enveloplambda = -1;
7005 nodedata->energylambda = -1;
7006
7007 nodedata->idx = j;
7008 nodedata->intheta = TRUE;
7009 }
7010
7011 nnodedatas = ncands;
7012
7013 /* sort (non-decreasing) the jobs w.r.t. latest completion times */
7014 SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
7015
7016 ninsertcands = 0;
7017
7018 /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
7019 * the root envelop detects an overload
7020 */
7021 for( j = 0; j < ncands; ++j )
7022 {
7023 SCIP_BTNODE* leaf;
7024 SCIP_NODEDATA* rootdata;
7025
7026 idx = nodedataidx[j];
7027
7028 /* check if the new job opens a time window which size is so large that it offers more energy than the total
7029 * energy of all candidate jobs. If so we skip that one.
7030 */
7031 if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
7032 {
7033 /* set the earliest start time to minus one to mark that candidate to be not used */
7034 nodedatas[idx].est = -1;
7035 continue;
7036 }
7037
7038 /* create search node */
7039 SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
7040
7041 /* insert new node into the theta set and updete the envelops */
7042 SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
7043 assert(nnodedatas <= 2*nvars);
7044
7045 /* move the inserted candidates together */
7046 leaves[ninsertcands] = leaf;
7047 ninsertcands++;
7048
7049 assert(!SCIPbtIsEmpty(tree));
7050 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
7051 assert(rootdata != NULL);
7052
7053 /* check if the theta set envelops exceeds the available capacity */
7054 if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
7055 {
7056 SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
7057 (*cutoff) = TRUE;
7058
7059 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
7061
7062 break;
7063 }
7064 }
7065
7066 /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7067 if( *cutoff )
7068 {
7069 int glbenery;
7070 int est;
7071 int lct;
7072
7073 glbenery = 0;
7074 assert( 0 <= idx );
7075 est = nodedatas[idx].est;
7076 lct = nodedatas[idx].lct;
7077
7078 /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7079 * which led to an overload
7080 */
7081 for( j = j+1; j < ncands; ++j )
7082 {
7084 int duration;
7085 int glbest;
7086 int glblct;
7087
7088 idx = nodedataidx[j];
7089 nodedata = &nodedatas[idx];
7090 assert(nodedata != NULL);
7091
7092 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7093
7094 /* get latest start time */
7096 glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7097
7098 /* check if parts of the jobs run with the time window defined by the last inserted job */
7099 if( glbest < est )
7100 duration -= (est - glbest);
7101
7102 if( glblct > lct )
7103 duration -= (glblct - lct);
7104
7105 if( duration > 0 )
7106 {
7107 glbenery += nodedata->demand * duration;
7108
7109 if( explanation != NULL )
7110 explanation[nodedata->idx] = TRUE;
7111 }
7112 }
7113
7114 /* analyze the overload */
7115 SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7116 conshdlrdata->usebdwidening, initialized, explanation) );
7117 }
7118 else if( ninsertcands > 1 && conshdlrdata->efinfer )
7119 {
7120 /* if we have more than one job insterted and edge-finding should be performed we do it */
7121 SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7122 propest, shift, initialized, explanation, nchgbds, cutoff) );
7123 }
7124
7125 /* free theta tree */
7126 SCIPbtFree(&tree);
7127
7128 /* free buffer arrays */
7129 SCIPfreeBufferArray(scip, &leaves);
7130 SCIPfreeBufferArray(scip, &nodedataidx);
7131 SCIPfreeBufferArray(scip, &nodedatas);
7132
7133 return SCIP_OKAY;
7134}
7135
7136/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7137 *
7138 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7139 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7140 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7141 */
7142static
7144 SCIP* scip, /**< SCIP data structure */
7145 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7146 int nvars, /**< number of start time variables (activities) */
7147 SCIP_VAR** vars, /**< array of start time variables */
7148 int* durations, /**< array of durations */
7149 int* demands, /**< array of demands */
7150 int capacity, /**< cumulative capacity */
7151 int hmin, /**< left bound of time axis to be considered (including hmin) */
7152 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7153 SCIP_CONS* cons, /**< constraint which is propagated */
7154 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7155 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7156 int* nchgbds, /**< pointer to store the number of bound changes */
7157 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7158 )
7159{
7160 /* check if a cutoff was already detected */
7161 if( (*cutoff) )
7162 return SCIP_OKAY;
7163
7164 /* check if at least the basic overload checking should be preformed */
7165 if( !conshdlrdata->efcheck )
7166 return SCIP_OKAY;
7167
7168 /* check for overload, which may result in a cutoff */
7169 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7170 cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7171
7172 /* check if a cutoff was detected */
7173 if( (*cutoff) )
7174 return SCIP_OKAY;
7175
7176 /* check if bound should be infer */
7177 if( !conshdlrdata->efinfer )
7178 return SCIP_OKAY;
7179
7180 /* check for overload, which may result in a cutoff */
7181 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7182 cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7183
7184 return SCIP_OKAY;
7185}
7186
7187/** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7188 * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7189 * event points
7190 */
7191static
7193 SCIP* scip, /**< SCIP data structure */
7194 int nvars, /**< number of start time variables (activities) */
7195 SCIP_VAR** vars, /**< array of start time variables */
7196 int* durations, /**< array of durations */
7197 int* demands, /**< array of demands */
7198 int capacity, /**< cumulative capacity */
7199 int hmin, /**< left bound of time axis to be considered (including hmin) */
7200 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7201 SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7202 )
7203{
7204 SCIP_VAR* var;
7205 int* starttimes; /* stores when each job is starting */
7206 int* endtimes; /* stores when each job ends */
7207 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7208 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7209
7210 int lb;
7211 int ub;
7212 int freecapacity; /* remaining capacity */
7213 int curtime; /* point in time which we are just checking */
7214 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7215 int njobs;
7216 int j;
7217
7218 assert(scip != NULL);
7219 assert(redundant != NULL);
7220
7221 (*redundant) = TRUE;
7222
7223 /* if no activities are associated with this cumulative then this constraint is redundant */
7224 if( nvars == 0 )
7225 return SCIP_OKAY;
7226
7227 assert(vars != NULL);
7228
7229 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7230 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7231 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7232 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7233
7234 njobs = 0;
7235
7236 /* assign variables, start and endpoints to arrays */
7237 for( j = 0; j < nvars; ++j )
7238 {
7239 assert(durations[j] > 0);
7240 assert(demands[j] > 0);
7241
7242 var = vars[j];
7243 assert(var != NULL);
7244
7247
7248 /* check if jobs runs completely outside of the effective time horizon */
7249 if( lb >= hmax || ub + durations[j] <= hmin )
7250 continue;
7251
7252 starttimes[njobs] = MAX(lb, hmin);
7253 startindices[njobs] = j;
7254
7255 endtimes[njobs] = MIN(ub + durations[j], hmax);
7256 endindices[njobs] = j;
7257 assert(starttimes[njobs] <= endtimes[njobs]);
7258 njobs++;
7259 }
7260
7261 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7262 SCIPsortIntInt(starttimes, startindices, njobs);
7263 SCIPsortIntInt(endtimes, endindices, njobs);
7264
7265 endindex = 0;
7266 freecapacity = capacity;
7267
7268 /* check each start point of a job whether the capacity is violated or not */
7269 for( j = 0; j < njobs; ++j )
7270 {
7271 curtime = starttimes[j];
7272
7273 /* stop checking, if time point is above hmax */
7274 if( curtime >= hmax )
7275 break;
7276
7277 /* subtract all capacity needed up to this point */
7278 freecapacity -= demands[startindices[j]];
7279 while( j+1 < njobs && starttimes[j+1] == curtime )
7280 {
7281 ++j;
7282 freecapacity -= demands[startindices[j]];
7283 }
7284
7285 /* free all capacity usages of jobs the are no longer running */
7286 while( endtimes[endindex] <= curtime )
7287 {
7288 freecapacity += demands[endindices[endindex]];
7289 ++endindex;
7290 }
7291 assert(freecapacity <= capacity);
7292
7293 /* check freecapacity to be smaller than zero */
7294 if( freecapacity < 0 && curtime >= hmin )
7295 {
7296 (*redundant) = FALSE;
7297 break;
7298 }
7299 } /*lint --e{850}*/
7300
7301 /* free all buffer arrays */
7302 SCIPfreeBufferArray(scip, &endindices);
7303 SCIPfreeBufferArray(scip, &startindices);
7304 SCIPfreeBufferArray(scip, &endtimes);
7305 SCIPfreeBufferArray(scip, &starttimes);
7306
7307 return SCIP_OKAY;
7308}
7309
7310/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7311 * completion time
7312 */
7313static
7315 SCIP* scip, /**< SCIP data structure */
7316 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7317 SCIP_PROFILE* profile, /**< resource profile */
7318 int nvars, /**< number of variables (jobs) */
7319 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7320 int* durations, /**< array containing corresponding durations */
7321 int* demands, /**< array containing corresponding demands */
7322 int capacity, /**< cumulative capacity */
7323 int hmin, /**< left bound of time axis to be considered (including hmin) */
7324 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7325 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7326 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7327 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7328 )
7329{
7330 int v;
7331
7332 /* insert all cores */
7333 for( v = 0; v < nvars; ++v )
7334 {
7335 SCIP_VAR* var;
7336 SCIP_Bool infeasible;
7337 int duration;
7338 int demand;
7339 int begin;
7340 int end;
7341 int est;
7342 int lst;
7343 int pos;
7344
7345 var = vars[v];
7346 assert(var != NULL);
7349
7350 duration = durations[v];
7351 assert(duration > 0);
7352
7353 demand = demands[v];
7354 assert(demand > 0);
7355
7356 /* collect earliest and latest start time */
7359
7360 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7361 if( lst + duration <= hmin || est >= hmax )
7362 continue;
7363
7364 /* compute core interval w.r.t. effective time horizon */
7365 begin = MAX(hmin, lst);
7366 end = MIN(hmax, est + duration);
7367
7368 /* check if a core exists */
7369 if( begin >= end )
7370 continue;
7371
7372 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7373 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7374
7375 /* insert the core into core resource profile (complexity O(log n)) */
7376 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7377
7378 /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7379 if( infeasible )
7380 {
7381 assert(begin <= SCIPprofileGetTime(profile, pos));
7382 assert(end > SCIPprofileGetTime(profile, pos));
7383
7384 /* use conflict analysis to analysis the core insertion which was infeasible */
7385 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7386 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7387
7388 if( explanation != NULL )
7389 explanation[v] = TRUE;
7390
7391 (*cutoff) = TRUE;
7392
7393 /* for the statistic we count the number of times a cutoff was detected due the time-time */
7395
7396 break;
7397 }
7398 }
7399
7400 return SCIP_OKAY;
7401}
7402
7403/** propagate the cumulative condition */
7404static
7406 SCIP* scip, /**< SCIP data structure */
7407 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7408 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7409 int nvars, /**< number of start time variables (activities) */
7410 SCIP_VAR** vars, /**< array of start time variables */
7411 int* durations, /**< array of durations */
7412 int* demands, /**< array of demands */
7413 int capacity, /**< cumulative capacity */
7414 int hmin, /**< left bound of time axis to be considered (including hmin) */
7415 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7416 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7417 int* nchgbds, /**< pointer to store the number of bound changes */
7418 SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7419 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7420 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7421 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7422 )
7423{
7424 SCIP_PROFILE* profile;
7425
7426 SCIP_RETCODE retcode = SCIP_OKAY;
7427
7428 assert(nchgbds != NULL);
7429 assert(initialized != NULL);
7430 assert(cutoff != NULL);
7431 assert(!(*cutoff));
7432
7433 /**@todo avoid always sorting the variable array */
7434
7435 /* check if the constraint is redundant */
7436 SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7437
7438 if( *redundant )
7439 return SCIP_OKAY;
7440
7441 /* create an empty resource profile for profiling the cores of the jobs */
7442 SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7443
7444 /* create core profile (compulsory parts) */
7445 SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7446 initialized, explanation, cutoff), TERMINATE );
7447
7448 /* propagate the job cores until nothing else can be detected */
7449 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7450 {
7451 SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7452 nchgbds, initialized, explanation, cutoff), TERMINATE );
7453 }
7454
7455 /* run edge finding propagator */
7456 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7457 {
7458 SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7459 cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7460 }
7461
7462 /* run time-table edge-finding propagator */
7463 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7464 {
7465 SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7466 nchgbds, initialized, explanation, cutoff), TERMINATE );
7467 }
7468 /* free resource profile */
7469TERMINATE:
7470 SCIPprofileFree(&profile);
7471
7472 return retcode;
7473}
7474
7475/** propagate the cumulative constraint */
7476static
7478 SCIP* scip, /**< SCIP data structure */
7479 SCIP_CONS* cons, /**< constraint to propagate */
7480 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7481 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7482 int* nchgbds, /**< pointer to store the number of bound changes */
7483 int* ndelconss, /**< pointer to store the number of deleted constraints */
7484 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7485 )
7486{
7487 SCIP_CONSDATA* consdata;
7488 SCIP_Bool initialized;
7489 SCIP_Bool redundant;
7490 int oldnchgbds;
7491
7492 assert(scip != NULL);
7493 assert(cons != NULL);
7494
7495 consdata = SCIPconsGetData(cons);
7496 assert(consdata != NULL);
7497
7498 oldnchgbds = *nchgbds;
7499 initialized = FALSE;
7500 redundant = FALSE;
7501
7502 if( SCIPconsIsDeleted(cons) )
7503 {
7504 assert(SCIPinProbing(scip));
7505 return SCIP_OKAY;
7506 }
7507
7508 /* if the constraint marked to be propagated, do nothing */
7509 if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7510 return SCIP_OKAY;
7511
7512 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7513 consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7514 consdata->hmin, consdata->hmax, cons,
7515 nchgbds, &redundant, &initialized, NULL, cutoff) );
7516
7517 if( redundant )
7518 {
7519 SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7520 SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7521
7522 if( !SCIPinProbing(scip) )
7523 {
7525 (*ndelconss)++;
7526 }
7527 }
7528 else
7529 {
7530 if( initialized )
7531 {
7532 /* run conflict analysis since it was initialized */
7533 assert(*cutoff == TRUE);
7534 SCIPdebugMsg(scip, "start conflict analysis\n");
7536 }
7537
7538 /* if successful, reset age of constraint */
7539 if( *cutoff || *nchgbds > oldnchgbds )
7540 {
7542 }
7543 else
7544 {
7545 /* mark the constraint to be propagated */
7546 consdata->propagated = TRUE;
7547 }
7548 }
7549
7550 return SCIP_OKAY;
7551}
7552
7553/** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7554 * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7555 * be realize as domain reduction. Otherwise we do nothing
7556 */
7557static
7559 SCIP* scip, /**< SCIP data structure */
7560 SCIP_VAR** vars, /**< problem variables */
7561 int nvars, /**< number of problem variables */
7562 int probingpos, /**< variable number to apply probing on */
7563 SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7564 SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7565 SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7566 SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7567 SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7568 SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7569 SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7570 SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7571 SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7572 SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7573 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7574 SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7575 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7576 )
7577{
7578 SCIP_VAR* var;
7579 SCIP_Bool tightened;
7580
7581 assert(probingpos >= 0);
7582 assert(probingpos < nvars);
7583 assert(success != NULL);
7584 assert(cutoff != NULL);
7585
7586 var = vars[probingpos];
7587 assert(var != NULL);
7588 assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7589 assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7590 assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7591 assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7592
7593 (*success) = FALSE;
7594
7596 return SCIP_OKAY;
7597
7598 /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7599 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7600 leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7601
7602 if( (*cutoff) )
7603 {
7604 /* note that cutoff may occur if presolving has not been executed fully */
7605 SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7606
7607 if( tightened )
7608 {
7609 (*success) =TRUE;
7610 (*nfixedvars)++;
7611 }
7612
7613 return SCIP_OKAY;
7614 }
7615
7616 /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7617 * presolving has not been executed fully
7618 */
7619 if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7620 {
7621 /* note that cutoff may occur if presolving has not been executed fully */
7622 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7623
7624 if( tightened )
7625 {
7626 (*success) = TRUE;
7627 (*nfixedvars)++;
7628 }
7629
7630 return SCIP_OKAY;
7631 }
7632
7633 /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7634 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7635 rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7636
7637 if( (*cutoff) )
7638 {
7639 /* note that cutoff may occur if presolving has not been executed fully */
7640 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7641
7642 if( tightened )
7643 {
7644 (*success) =TRUE;
7645 (*nfixedvars)++;
7646 }
7647
7648 return SCIP_OKAY;
7649 }
7650
7651 return SCIP_OKAY;
7652}
7653
7654/** is it possible, to round variable down w.r.t. objective function */
7655static
7657 SCIP* scip, /**< SCIP data structure */
7658 SCIP_VAR* var, /**< problem variable */
7659 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7660 )
7661{
7662 SCIP_Real objval;
7663 int scalar;
7664
7665 assert(roundable != NULL);
7666
7667 *roundable = TRUE;
7668
7669 /* a fixed variable can be definition always be safely rounded */
7671 return SCIP_OKAY;
7672
7673 /* in case the variable is not active we need to check the object coefficient of the active variable */
7674 if( !SCIPvarIsActive(var) )
7675 {
7676 SCIP_VAR* actvar;
7677 int constant;
7678
7679 actvar = var;
7680
7681 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7682 assert(scalar != 0);
7683
7684 objval = scalar * SCIPvarGetObj(actvar);
7685 } /*lint !e438*/
7686 else
7687 {
7688 scalar = 1;
7689 objval = SCIPvarGetObj(var);
7690 }
7691
7692 /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7693 * (the transformed problem is always a minimization problem)
7694 *
7695 * @note that we need to check this condition w.r.t. active variable space
7696 */
7697 if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7698 *roundable = FALSE;
7699
7700 return SCIP_OKAY;
7701}
7702
7703/** is it possible, to round variable up w.r.t. objective function */
7704static
7706 SCIP* scip, /**< SCIP data structure */
7707 SCIP_VAR* var, /**< problem variable */
7708 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7709 )
7710{
7711 SCIP_Real objval;
7712 int scalar;
7713
7714 assert(roundable != NULL);
7715
7716 *roundable = TRUE;
7717
7718 /* a fixed variable can be definition always be safely rounded */
7720 return SCIP_OKAY;
7721
7722 /* in case the variable is not active we need to check the object coefficient of the active variable */
7723 if( !SCIPvarIsActive(var) )
7724 {
7725 SCIP_VAR* actvar;
7726 int constant;
7727
7728 actvar = var;
7729
7730 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7731 assert(scalar != 0);
7732
7733 objval = scalar * SCIPvarGetObj(actvar);
7734 } /*lint !e438*/
7735 else
7736 {
7737 scalar = 1;
7738 objval = SCIPvarGetObj(var);
7739 }
7740
7741 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7742 * (the transformed problem is always a minimization problem)
7743 *
7744 * @note that we need to check this condition w.r.t. active variable space
7745 */
7746 if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7747 *roundable = FALSE;
7748
7749 return SCIP_OKAY;
7750}
7751
7752/** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7753 * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7754 * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7755 * the only one locking this variable in the corresponding direction.
7756 */
7757static
7759 SCIP* scip, /**< SCIP data structure */
7760 SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7761 int nconss, /**< number of cumulative constraints */
7762 SCIP_Bool local, /**< use local bounds effective horizon? */
7763 int* alternativelbs, /**< alternative lower bounds */
7764 int* alternativeubs, /**< alternative lower bounds */
7765 int* downlocks, /**< number of constraints with down lock participating by the computation */
7766 int* uplocks /**< number of constraints with up lock participating by the computation */
7767 )
7768{
7769 int nvars;
7770 int c;
7771 int v;
7772
7773 for( c = 0; c < nconss; ++c )
7774 {
7775 SCIP_CONSDATA* consdata;
7776 SCIP_CONS* cons;
7777 SCIP_VAR* var;
7778 int hmin;
7779 int hmax;
7780
7781 cons = conss[c];
7782 assert(cons != NULL);
7783
7784 /* ignore constraints which are already deletet and those which are not check constraints */
7785 if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7786 continue;
7787
7788 consdata = SCIPconsGetData(cons);
7789 assert(consdata != NULL);
7790 assert(consdata->nvars > 1);
7791
7792 /* compute the hmin and hmax */
7793 if( local )
7794 {
7795 SCIP_PROFILE* profile;
7796 SCIP_RETCODE retcode;
7797
7798 /* create empty resource profile with infinity resource capacity */
7799 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7800
7801 /* create worst case resource profile */
7802 retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7803
7804 hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7805 hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7806
7807 /* free worst case profile */
7808 SCIPprofileFree(&profile);
7809
7810 if( retcode != SCIP_OKAY )
7811 return retcode;
7812 }
7813 else
7814 {
7815 hmin = consdata->hmin;
7816 hmax = consdata->hmax;
7817 }
7818
7819 consdata = SCIPconsGetData(cons);
7820 assert(consdata != NULL);
7821
7822 nvars = consdata->nvars;
7823
7824 for( v = 0; v < nvars; ++v )
7825 {
7826 int scalar;
7827 int constant;
7828 int idx;
7829
7830 var = consdata->vars[v];
7831 assert(var != NULL);
7832
7833 /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7835
7836 /* ignore variable locally fixed variables */
7837 if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7838 continue;
7839
7840 SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7841 idx = SCIPvarGetProbindex(var);
7842 assert(idx >= 0);
7843
7844 /* first check lower bound fixing */
7845 if( consdata->downlocks[v] )
7846 {
7847 int ect;
7848 int est;
7849
7850 /* the variable has a down locked */
7851 est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7852 ect = est + consdata->durations[v];
7853
7854 if( ect <= hmin || hmin >= hmax )
7855 downlocks[idx]++;
7856 else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7857 {
7858 alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7859 downlocks[idx]++;
7860 }
7861 }
7862
7863 /* second check upper bound fixing */
7864 if( consdata->uplocks[v] )
7865 {
7866 int duration;
7867 int lct;
7868 int lst;
7869
7870 duration = consdata->durations[v];
7871
7872 /* the variable has a up lock locked */
7873 lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7874 lct = lst + duration;
7875
7876 if( lst >= hmax || hmin >= hmax )
7877 uplocks[idx]++;
7878 else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7879 {
7880 alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7881 uplocks[idx]++;
7882 }
7883 }
7884 }
7885 }
7886
7887 return SCIP_OKAY;
7888}
7889
7890/** apply all fixings which are given by the alternative bounds */
7891static
7893 SCIP* scip, /**< SCIP data structure */
7894 SCIP_VAR** vars, /**< array of active variables */
7895 int nvars, /**< number of active variables */
7896 int* alternativelbs, /**< alternative lower bounds */
7897 int* alternativeubs, /**< alternative lower bounds */
7898 int* downlocks, /**< number of constraints with down lock participating by the computation */
7899 int* uplocks, /**< number of constraints with up lock participating by the computation */
7900 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7901 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7902 )
7903{
7904 SCIP_Real* downimpllbs;
7905 SCIP_Real* downimplubs;
7906 SCIP_Real* downproplbs;
7907 SCIP_Real* downpropubs;
7908 SCIP_Real* upimpllbs;
7909 SCIP_Real* upimplubs;
7910 SCIP_Real* upproplbs;
7911 SCIP_Real* uppropubs;
7912 int v;
7913
7914 /* get temporary memory for storing probing results */
7915 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7916 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7917 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7918 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7919 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7920 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7921 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7922 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7923
7924 for( v = 0; v < nvars; ++v )
7925 {
7926 SCIP_VAR* var;
7927 SCIP_Bool infeasible;
7928 SCIP_Bool fixed;
7929 SCIP_Bool roundable;
7930 int ub;
7931 int lb;
7932
7933 var = vars[v];
7934 assert(var != NULL);
7935
7936 /* ignore variables for which no alternative bounds have been computed */
7937 if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7938 continue;
7939
7942
7943 /* ignore fixed variables */
7944 if( ub - lb <= 0 )
7945 continue;
7946
7947 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7948 {
7949 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7950
7951 if( roundable )
7952 {
7953 if( alternativelbs[v] > ub )
7954 {
7955 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7956 assert(!infeasible);
7957 assert(fixed);
7958
7959 (*nfixedvars)++;
7960
7961 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7962 * constraints
7963 */
7965 }
7966 else
7967 {
7968 SCIP_Bool success;
7969
7970 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7971 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7972 * infeasible we can apply the dual reduction; otherwise we do nothing
7973 */
7974 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7975 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7976 nfixedvars, &success, cutoff) );
7977
7978 if( success )
7979 {
7981 }
7982 }
7983 }
7984 }
7985
7988
7989 /* ignore fixed variables */
7990 if( ub - lb <= 0 )
7991 continue;
7992
7993 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7994 {
7995 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7996
7997 if( roundable )
7998 {
7999 if( alternativeubs[v] < lb )
8000 {
8001 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
8002 assert(!infeasible);
8003 assert(fixed);
8004
8005 (*nfixedvars)++;
8006
8007 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
8008 * constraints
8009 */
8011 }
8012 else
8013 {
8014 SCIP_Bool success;
8015
8016 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
8017 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
8018 * infeasible we can apply the dual reduction; otherwise we do nothing
8019 */
8020 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
8021 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
8022 nfixedvars, &success, cutoff) );
8023
8024 if( success )
8025 {
8027 }
8028 }
8029 }
8030 }
8031 }
8032
8033 /* free temporary memory */
8034 SCIPfreeBufferArray(scip, &uppropubs);
8035 SCIPfreeBufferArray(scip, &upproplbs);
8036 SCIPfreeBufferArray(scip, &upimplubs);
8037 SCIPfreeBufferArray(scip, &upimpllbs);
8038 SCIPfreeBufferArray(scip, &downpropubs);
8039 SCIPfreeBufferArray(scip, &downproplbs);
8040 SCIPfreeBufferArray(scip, &downimplubs);
8041 SCIPfreeBufferArray(scip, &downimpllbs);
8042
8043 return SCIP_OKAY;
8044}
8045
8046/** propagate all constraints together */
8047static
8049 SCIP* scip, /**< SCIP data structure */
8050 SCIP_CONS** conss, /**< all cumulative constraint */
8051 int nconss, /**< number of cumulative constraints */
8052 SCIP_Bool local, /**< use local bounds effective horizon? */
8053 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
8054 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
8055 SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
8056 )
8057{ /*lint --e{715}*/
8058 SCIP_VAR** vars;
8059 int* downlocks;
8060 int* uplocks;
8061 int* alternativelbs;
8062 int* alternativeubs;
8063 int oldnfixedvars;
8064 int nvars;
8065 int v;
8066
8068 return SCIP_OKAY;
8069
8070 nvars = SCIPgetNVars(scip);
8071 oldnfixedvars = *nfixedvars;
8072
8073 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8074 SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8075 SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8076 SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8077 SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8078
8079 /* initialize arrays */
8080 for( v = 0; v < nvars; ++v )
8081 {
8082 downlocks[v] = 0;
8083 uplocks[v] = 0;
8084 alternativelbs[v] = INT_MAX;
8085 alternativeubs[v] = INT_MIN;
8086 }
8087
8088 /* compute alternative bounds */
8089 SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8090
8091 /* apply fixing which result of the alternative bounds directly */
8092 SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8093 nfixedvars, cutoff) );
8094
8095 if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8096 {
8097 SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8098 }
8099
8100 /* free all buffers */
8101 SCIPfreeBufferArray(scip, &alternativeubs);
8102 SCIPfreeBufferArray(scip, &alternativelbs);
8103 SCIPfreeBufferArray(scip, &uplocks);
8104 SCIPfreeBufferArray(scip, &downlocks);
8105 SCIPfreeBufferArray(scip, &vars);
8106
8107 return SCIP_OKAY;
8108}
8109
8110/**@} */
8111
8112/**@name Linear relaxations
8113 *
8114 * @{
8115 */
8116
8117/** creates covering cuts for jobs violating resource constraints */
8118static
8120 SCIP* scip, /**< SCIP data structure */
8121 SCIP_CONS* cons, /**< constraint to be checked */
8122 int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8123 int time /**< at this point in time covering constraints are valid */
8124 )
8125{
8126 SCIP_CONSDATA* consdata;
8127 SCIP_ROW* row;
8128 int* flexibleids;
8129 int* demands;
8130
8131 char rowname[SCIP_MAXSTRLEN];
8132
8133 int remainingcap;
8134 int smallcoversize; /* size of a small cover */
8135 int bigcoversize; /* size of a big cover */
8136 int nvars;
8137
8138 int nflexible;
8139 int sumdemand; /* demand of all jobs up to a certain index */
8140 int j;
8141
8142 assert(cons != NULL);
8143
8144 /* get constraint data structure */
8145 consdata = SCIPconsGetData(cons);
8146 assert(consdata != NULL );
8147
8148 nvars = consdata->nvars;
8149
8150 /* sort jobs according to demands */
8151 SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8152 SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8153
8154 nflexible = 0;
8155 remainingcap = consdata->capacity;
8156
8157 /* get all jobs intersecting point 'time' with their bounds */
8158 for( j = 0; j < nvars; ++j )
8159 {
8160 int ub;
8161
8162 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8163
8164 /* only add jobs to array if they intersect with point 'time' */
8165 if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8166 {
8167 /* if job is fixed, capacity has to be decreased */
8168 if( startvalues[j] == ub )
8169 {
8170 remainingcap -= consdata->demands[j];
8171 }
8172 else
8173 {
8174 demands[nflexible] = consdata->demands[j];
8175 flexibleids[nflexible] = j;
8176 ++nflexible;
8177 }
8178 }
8179 }
8180 assert(remainingcap >= 0);
8181
8182 /* sort demands and job ids */
8183 SCIPsortIntInt(demands, flexibleids, nflexible);
8184
8185 /*
8186 * version 1:
8187 * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8188 * erzeuge cover constraint
8189 *
8190 */
8191
8192 /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8193 sumdemand = 0;
8194 j = 0;
8195
8196 while( j < nflexible && sumdemand <= remainingcap )
8197 {
8198 sumdemand += demands[j];
8199 j++;
8200 }
8201
8202 /* j jobs form a conflict, set coversize to 'j - 1' */
8203 bigcoversize = j-1;
8204 assert(sumdemand > remainingcap);
8205 assert(bigcoversize < nflexible);
8206
8207 /* - create a row for all jobs and their binary variables.
8208 * - at most coversize many binary variables of jobs can be set to one
8209 */
8210
8211 /* construct row name */
8212 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8213 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8214 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8216
8217 for( j = 0; j < nflexible; ++j )
8218 {
8219 SCIP_VAR** binvars;
8220 SCIP_Real* vals;
8221 int nbinvars;
8222 int idx;
8223 int start;
8224 int end;
8225 int lb;
8226 int ub;
8227 int b;
8228
8229 idx = flexibleids[j];
8230
8231 /* get and add binvars into var array */
8232 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8233 assert(nbinvars != 0);
8234
8235 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8236 assert(vals != NULL);
8237
8238 lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8239 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8240
8241 /* compute start and finishing time */
8242 start = time - consdata->durations[idx] + 1;
8243 end = MIN(time, ub);
8244
8245 /* add all neccessary binary variables */
8246 for( b = 0; b < nbinvars; ++b )
8247 {
8248 if( vals[b] < start || vals[b] < lb )
8249 continue;
8250
8251 if( vals[b] > end )
8252 break;
8253
8254 assert(binvars[b] != NULL);
8255 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8256 }
8257 }
8258
8259 /* insert and release row */
8261
8262 if( consdata->bcoverrowssize == 0 )
8263 {
8264 consdata->bcoverrowssize = 10;
8265 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8266 }
8267 if( consdata->nbcoverrows == consdata->bcoverrowssize )
8268 {
8269 consdata->bcoverrowssize *= 2;
8270 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8271 }
8272
8273 consdata->bcoverrows[consdata->nbcoverrows] = row;
8274 consdata->nbcoverrows++;
8275
8276 /*
8277 * version 2:
8278 * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8279 * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8280 */
8281 /* find maximum number of jobs that can run in parallel (= coversize -1) */
8282 sumdemand = 0;
8283 j = nflexible -1;
8284 while( sumdemand <= remainingcap )
8285 {
8286 assert(j >= 0);
8287 sumdemand += demands[j];
8288 j--;
8289 }
8290
8291 smallcoversize = nflexible - (j + 1) - 1;
8292 while( j > 0 && demands[j] == demands[nflexible-1] )
8293 --j;
8294
8295 assert(smallcoversize < nflexible);
8296
8297 if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8298 {
8299 /* construct row name */
8300 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8301 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8302 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8304
8305 /* filter binary variables for each unfixed job */
8306 for( j = j + 1; j < nflexible; ++j )
8307 {
8308 SCIP_VAR** binvars;
8309 SCIP_Real* vals;
8310 int nbinvars;
8311 int idx;
8312 int start;
8313 int end;
8314 int lb;
8315 int ub;
8316 int b;
8317
8318 idx = flexibleids[j];
8319
8320 /* get and add binvars into var array */
8321 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8322 assert(nbinvars != 0);
8323
8324 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8325 assert(vals != NULL);
8326
8327 lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8328 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8329
8330 /* compute start and finishing time */
8331 start = time - consdata->durations[idx] + 1;
8332 end = MIN(time, ub);
8333
8334 /* add all neccessary binary variables */
8335 for( b = 0; b < nbinvars; ++b )
8336 {
8337 if( vals[b] < start || vals[b] < lb )
8338 continue;
8339
8340 if( vals[b] > end )
8341 break;
8342
8343 assert(binvars[b] != NULL);
8344 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8345 }
8346 }
8347
8348 /* insert and release row */
8350 if( consdata->scoverrowssize == 0 )
8351 {
8352 consdata->scoverrowssize = 10;
8353 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8354 }
8355 if( consdata->nscoverrows == consdata->scoverrowssize )
8356 {
8357 consdata->scoverrowssize *= 2;
8358 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8359 }
8360
8361 consdata->scoverrows[consdata->nscoverrows] = row;
8362 consdata->nscoverrows++;
8363 }
8364
8365 /* free buffer arrays */
8366 SCIPfreeBufferArray(scip, &flexibleids);
8367 SCIPfreeBufferArray(scip, &demands);
8368
8369 return SCIP_OKAY;
8370}
8371
8372/** method to construct cover cuts for all points in time */
8373static
8375 SCIP* scip, /**< SCIP data structure */
8376 SCIP_CONS* cons /**< constraint to be separated */
8377 )
8378{
8379 SCIP_CONSDATA* consdata;
8380
8381 int* startvalues; /* stores when each job is starting */
8382 int* endvalues; /* stores when each job ends */
8383 int* startvaluessorted; /* stores when each job is starting */
8384 int* endvaluessorted; /* stores when each job ends */
8385 int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8386 int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8387
8388 int nvars; /* number of jobs for this constraint */
8389 int freecapacity; /* remaining capacity */
8390 int curtime; /* point in time which we are just checking */
8391 int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8392
8393 int hmin;
8394 int hmax;
8395
8396 int j;
8397 int t;
8398
8399 assert(scip != NULL);
8400 assert(cons != NULL);
8401
8402 consdata = SCIPconsGetData(cons);
8403 assert(consdata != NULL);
8404
8405 /* if no activities are associated with this resource then this constraint is redundant */
8406 if( consdata->vars == NULL )
8407 return SCIP_OKAY;
8408
8409 nvars = consdata->nvars;
8410 hmin = consdata->hmin;
8411 hmax = consdata->hmax;
8412
8413 SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8414 SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8415 SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8416 SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8417 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8418 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8419
8420 /* assign start and endpoints to arrays */
8421 for ( j = 0; j < nvars; ++j )
8422 {
8423 startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8424 startvaluessorted[j] = startvalues[j];
8425
8426 endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8427 endvaluessorted[j] = endvalues[j];
8428
8429 startindices[j] = j;
8430 endindices[j] = j;
8431 }
8432
8433 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8434 * (and sort the indices in the same way) */
8435 SCIPsortIntInt(startvaluessorted, startindices, nvars);
8436 SCIPsortIntInt(endvaluessorted, endindices, nvars);
8437
8438 endidx = 0;
8439 freecapacity = consdata->capacity;
8440
8441 /* check each startpoint of a job whether the capacity is kept or not */
8442 for( j = 0; j < nvars; ++j )
8443 {
8444 curtime = startvaluessorted[j];
8445 if( curtime >= hmax )
8446 break;
8447
8448 /* subtract all capacity needed up to this point */
8449 freecapacity -= consdata->demands[startindices[j]];
8450
8451 while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8452 {
8453 ++j;
8454 freecapacity -= consdata->demands[startindices[j]];
8455 }
8456
8457 /* free all capacity usages of jobs the are no longer running */
8458 while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8459 {
8460 freecapacity += consdata->demands[endindices[endidx]];
8461 ++endidx;
8462 }
8463
8464 assert(freecapacity <= consdata->capacity);
8465 assert(endidx <= nvars);
8466
8467 /* --> endindex - points to the next job which will finish
8468 * j - points to the last job that has been released
8469 */
8470
8471 /* check freecapacity to be smaller than zero
8472 * then we will add cover constraints to the MIP
8473 */
8474 if( freecapacity < 0 && curtime >= hmin )
8475 {
8476 int nextprofilechange;
8477
8478 /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8479 if( j < nvars-1 )
8480 nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8481 else
8482 nextprofilechange = endvaluessorted[endidx];
8483
8484 nextprofilechange = MIN(nextprofilechange, hmax);
8485
8486 for( t = curtime; t < nextprofilechange; ++t )
8487 {
8488 SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8489
8490 /* create covering constraint */
8491 SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8492 }
8493 } /* end if freecapacity > 0 */
8494 } /*lint --e{850}*/
8495
8496 consdata->covercuts = TRUE;
8497
8498 /* free all buffer arrays */
8499 SCIPfreeBufferArray(scip, &endindices);
8500 SCIPfreeBufferArray(scip, &startindices);
8501 SCIPfreeBufferArray(scip, &endvaluessorted);
8502 SCIPfreeBufferArray(scip, &startvaluessorted);
8503 SCIPfreeBufferArray(scip, &endvalues);
8504 SCIPfreeBufferArray(scip, &startvalues);
8505
8506 return SCIP_OKAY;
8507}
8508
8509/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8510 * constraint
8511 */
8512static
8514 SCIP* scip, /**< SCIP data structure */
8515 SCIP_CONS* cons, /**< constraint to be checked */
8516 int* startindices, /**< permutation with rspect to the start times */
8517 int curtime, /**< current point in time */
8518 int nstarted, /**< number of jobs that start before the curtime or at curtime */
8519 int nfinished, /**< number of jobs that finished before curtime or at curtime */
8520 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8521 )
8522{
8523 SCIP_CONSDATA* consdata;
8524 SCIP_VAR** binvars;
8525 int* coefs;
8526 int nbinvars;
8527 char name[SCIP_MAXSTRLEN];
8528 int capacity;
8529 int b;
8530
8531 assert(nstarted > nfinished);
8532
8533 consdata = SCIPconsGetData(cons);
8534 assert(consdata != NULL);
8535 assert(consdata->nvars > 0);
8536
8537 capacity = consdata->capacity;
8538 assert(capacity > 0);
8539
8540 nbinvars = 0;
8541 SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8542
8543 /* construct row name */
8544 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8545
8546 if( cutsasconss )
8547 {
8548 SCIP_CONS* lincons;
8549
8550 /* create knapsack constraint for the given time point */
8551 SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8553
8554 for( b = 0; b < nbinvars; ++b )
8555 {
8556 SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8557 }
8558
8559 /* add and release the new constraint */
8560 SCIP_CALL( SCIPaddCons(scip, lincons) );
8561 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8562 }
8563 else
8564 {
8565 SCIP_ROW* row;
8566
8567 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8569
8570 for( b = 0; b < nbinvars; ++b )
8571 {
8572 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8573 }
8574
8577
8578 if( consdata->demandrowssize == 0 )
8579 {
8580 consdata->demandrowssize = 10;
8581 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8582 }
8583 if( consdata->ndemandrows == consdata->demandrowssize )
8584 {
8585 consdata->demandrowssize *= 2;
8586 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8587 }
8588
8589 consdata->demandrows[consdata->ndemandrows] = row;
8590 consdata->ndemandrows++;
8591 }
8592
8593 SCIPfreeBufferArrayNull(scip, &binvars);
8595
8596 return SCIP_OKAY;
8597}
8598
8599/** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8600 * row
8601 */
8602static
8604 SCIP* scip, /**< SCIP data structure */
8605 SCIP_CONS* cons, /**< constraint to be checked */
8606 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8607 )
8608{
8609 SCIP_CONSDATA* consdata;
8610
8611 int* starttimes; /* stores when each job is starting */
8612 int* endtimes; /* stores when each job ends */
8613 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8614 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8615
8616 int nvars; /* number of activities for this constraint */
8617 int freecapacity; /* remaining capacity */
8618 int curtime; /* point in time which we are just checking */
8619 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8620
8621 int hmin;
8622 int hmax;
8623
8624 int j;
8625
8626 assert(scip != NULL);
8627 assert(cons != NULL);
8628
8629 consdata = SCIPconsGetData(cons);
8630 assert(consdata != NULL);
8631
8632 nvars = consdata->nvars;
8633
8634 /* if no activities are associated with this cumulative then this constraint is redundant */
8635 if( nvars == 0 )
8636 return SCIP_OKAY;
8637
8638 assert(consdata->vars != NULL);
8639
8640 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8641 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8642 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8643 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8644
8645 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8646 SCIPconsGetName(cons), nvars);
8647
8648 /* create event point arrays */
8649 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8650 starttimes, endtimes, startindices, endindices, FALSE);
8651
8652 endindex = 0;
8653 freecapacity = consdata->capacity;
8654 hmin = consdata->hmin;
8655 hmax = consdata->hmax;
8656
8657 /* check each startpoint of a job whether the capacity is kept or not */
8658 for( j = 0; j < nvars; ++j )
8659 {
8660 curtime = starttimes[j];
8661 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8662
8663 if( curtime >= hmax )
8664 break;
8665
8666 /* remove the capacity requirments for all job which start at the curtime */
8667 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8668
8669 /* add the capacity requirments for all job which end at the curtime */
8670 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8671
8672 assert(freecapacity <= consdata->capacity);
8673 assert(endindex <= nvars);
8674
8675 /* endindex - points to the next job which will finish */
8676 /* j - points to the last job that has been released */
8677
8678 /* if free capacity is smaller than zero, then add rows to the LP */
8679 if( freecapacity < 0 && curtime >= hmin )
8680 {
8681 int nextstarttime;
8682 int t;
8683
8684 /* step forward until next job is released and see whether capacity constraint is met or not */
8685 if( j < nvars-1 )
8686 nextstarttime = starttimes[j+1];
8687 else
8688 nextstarttime = endtimes[nvars-1];
8689
8690 nextstarttime = MIN(nextstarttime, hmax);
8691
8692 /* create capacity restriction row for current event point */
8693 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8694
8695 /* create for all points in time between the current event point and next start event point a row if the free
8696 * capacity is still smaller than zero */
8697 for( t = curtime+1 ; t < nextstarttime; ++t )
8698 {
8699 /* add the capacity requirments for all job which end at the curtime */
8700 addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8701
8702 if( freecapacity < 0 )
8703 {
8704 /* add constraint */
8705 SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8706
8707 /* create capacity restriction row */
8708 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8709 }
8710 else
8711 break;
8712 }
8713 }
8714 } /*lint --e{850}*/
8715
8716 /* free all buffer arrays */
8717 SCIPfreeBufferArray(scip, &endindices);
8718 SCIPfreeBufferArray(scip, &startindices);
8719 SCIPfreeBufferArray(scip, &endtimes);
8720 SCIPfreeBufferArray(scip, &starttimes);
8721
8722 return SCIP_OKAY;
8723}
8724
8725/** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8726 * capacity is larger than the capacity of the cumulative constraint
8727 * - for each necessary point in time:
8728 *
8729 * sum_j sum_t demand_j * x_{j,t} <= capacity
8730 *
8731 * where x(j,t) is the binary variables of job j at time t
8732 */
8733static
8735 SCIP* scip, /**< SCIP data structure */
8736 SCIP_CONS* cons, /**< cumulative constraint */
8737 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8738 )
8739{
8740 SCIP_CONSDATA* consdata;
8741
8742 consdata = SCIPconsGetData(cons);
8743 assert(consdata != NULL);
8744 assert(consdata->demandrows == NULL);
8745 assert(consdata->ndemandrows == 0);
8746
8747 /* collect the linking constraints */
8748 if( consdata->linkingconss == NULL )
8749 {
8751 }
8752
8753 SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8754
8755 /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8756 if( cutsasconss )
8757 {
8758 if( SCIPconsIsInitial(cons) )
8759 {
8761 }
8762 if( SCIPconsIsSeparated(cons) )
8763 {
8765 }
8766 if( SCIPconsIsEnforced(cons) )
8767 {
8769 }
8770 }
8771
8772 return SCIP_OKAY;
8773}
8774
8775/** adds linear relaxation of cumulative constraint to the LP */
8776static
8778 SCIP* scip, /**< SCIP data structure */
8779 SCIP_CONS* cons, /**< cumulative constraint */
8780 SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8781 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8782 )
8783{
8784 SCIP_CONSDATA* consdata;
8785 int r;
8786
8787 consdata = SCIPconsGetData(cons);
8788 assert(consdata != NULL);
8789
8790 if( consdata->demandrows == NULL )
8791 {
8792 assert(consdata->ndemandrows == 0);
8793
8794 SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8795
8796 return SCIP_OKAY;
8797 }
8798
8799 for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8800 {
8801 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8802 {
8803 assert(consdata->demandrows[r] != NULL);
8804 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8805 }
8806 }
8807
8808 return SCIP_OKAY;
8809}
8810
8811/** checks constraint for violation, and adds it as a cut if possible */
8812static
8814 SCIP* scip, /**< SCIP data structure */
8815 SCIP_CONS* cons, /**< cumulative constraint to be separated */
8816 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8817 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8818 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8819 )
8820{ /*lint --e{715}*/
8821 SCIP_CONSDATA* consdata;
8822 int ncuts;
8823 int r;
8824
8825 assert(scip != NULL);
8826 assert(cons != NULL);
8827 assert(separated != NULL);
8828 assert(cutoff != NULL);
8829
8830 *separated = FALSE;
8831 *cutoff = FALSE;
8832
8833 consdata = SCIPconsGetData(cons);
8834 assert(consdata != NULL);
8835
8836 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8837
8838 if( consdata->demandrows == NULL )
8839 {
8840 assert(consdata->ndemandrows == 0);
8841
8843
8844 return SCIP_OKAY;
8845 }
8846
8847 ncuts = 0;
8848
8849 /* check each row that is not contained in LP */
8850 for( r = 0; r < consdata->ndemandrows; ++r )
8851 {
8852 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8853 {
8854 SCIP_Real feasibility;
8855
8856 if( sol != NULL )
8857 feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8858 else
8859 feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8860
8861 if( SCIPisFeasNegative(scip, feasibility) )
8862 {
8863 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8864 if ( *cutoff )
8865 {
8867 return SCIP_OKAY;
8868 }
8869 *separated = TRUE;
8870 ncuts++;
8871 }
8872 }
8873 }
8874
8875 if( ncuts > 0 )
8876 {
8877 SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8878
8879 /* if successful, reset age of constraint */
8881 (*separated) = TRUE;
8882 }
8883
8884 return SCIP_OKAY;
8885}
8886
8887/** checks constraint for violation, and adds it as a cut if possible */
8888static
8890 SCIP* scip, /**< SCIP data structure */
8891 SCIP_CONS* cons, /**< logic or constraint to be separated */
8892 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8893 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8894 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8895 )
8896{
8897 SCIP_CONSDATA* consdata;
8898 SCIP_ROW* row;
8899 SCIP_Real minfeasibility;
8900 int r;
8901
8902 assert(scip != NULL);
8903 assert(cons != NULL);
8904 assert(separated != NULL);
8905 assert(cutoff != NULL);
8906
8907 *separated = FALSE;
8908 *cutoff = FALSE;
8909
8910 consdata = SCIPconsGetData(cons);
8911 assert(consdata != NULL);
8912
8913 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8914
8915 /* collect the linking constraints */
8916 if( consdata->linkingconss == NULL )
8917 {
8919 }
8920
8921 if( !consdata->covercuts )
8922 {
8923 SCIP_CALL( createCoverCuts(scip, cons) );
8924 }
8925
8926 row = NULL;
8927 minfeasibility = SCIPinfinity(scip);
8928
8929 /* check each row of small covers that is not contained in LP */
8930 for( r = 0; r < consdata->nscoverrows; ++r )
8931 {
8932 if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8933 {
8934 SCIP_Real feasibility;
8935
8936 assert(consdata->scoverrows[r] != NULL);
8937 if( sol != NULL )
8938 feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8939 else
8940 feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8941
8942 if( minfeasibility > feasibility )
8943 {
8944 minfeasibility = feasibility;
8945 row = consdata->scoverrows[r];
8946 }
8947 }
8948 }
8949
8950 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8951
8952 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8953 {
8954 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8955 SCIPconsGetName(cons), minfeasibility);
8956
8957 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8959 if ( *cutoff )
8960 return SCIP_OKAY;
8961 (*separated) = TRUE;
8962 }
8963
8964 minfeasibility = SCIPinfinity(scip);
8965 row = NULL;
8966
8967 /* check each row of small covers that is not contained in LP */
8968 for( r = 0; r < consdata->nbcoverrows; ++r )
8969 {
8970 if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8971 {
8972 SCIP_Real feasibility;
8973
8974 assert(consdata->bcoverrows[r] != NULL);
8975 if( sol != NULL )
8976 feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8977 else
8978 feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8979
8980 if( minfeasibility > feasibility )
8981 {
8982 minfeasibility = feasibility;
8983 row = consdata->bcoverrows[r];
8984 }
8985 }
8986 }
8987
8988 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8989
8990 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8991 {
8992 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8993 SCIPconsGetName(cons), minfeasibility);
8994
8995 assert(row != NULL);
8996 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8998 if ( *cutoff )
8999 return SCIP_OKAY;
9000 (*separated) = TRUE;
9001 }
9002
9003 return SCIP_OKAY;
9004}
9005
9006/** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
9007static
9009 SCIP* scip, /**< SCIP data structure */
9010 SCIP_CONS* cons, /**< constraint to be checked */
9011 int* startindices, /**< permutation with rspect to the start times */
9012 int curtime, /**< current point in time */
9013 int nstarted, /**< number of jobs that start before the curtime or at curtime */
9014 int nfinished, /**< number of jobs that finished before curtime or at curtime */
9015 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
9016 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9017 )
9018{
9019 SCIP_CONSDATA* consdata;
9020 char name[SCIP_MAXSTRLEN];
9021 int lhs; /* left hand side of constraint */
9022
9023 SCIP_VAR** activevars;
9024 SCIP_ROW* row;
9025
9026 int v;
9027
9028 assert(nstarted > nfinished);
9029
9030 consdata = SCIPconsGetData(cons);
9031 assert(consdata != NULL);
9032 assert(consdata->nvars > 0);
9033
9034 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
9035
9036 SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
9037
9038 if( lower )
9039 {
9040 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
9041
9042 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
9043 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9044 }
9045 else
9046 {
9047 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
9048 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
9049 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9050 }
9051
9053
9054 for( v = 0; v < nstarted - nfinished; ++v )
9055 {
9056 SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9057 }
9058
9061
9062 SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
9063
9064 SCIP_CALL( SCIPreleaseRow(scip, &row) );
9065
9066 /* free buffers */
9067 SCIPfreeBufferArrayNull(scip, &activevars);
9068
9069 return SCIP_OKAY;
9070}
9071
9072/** checks constraint for violation, and adds it as a cut if possible */
9073static
9075 SCIP* scip, /**< SCIP data structure */
9076 SCIP_CONS* cons, /**< cumulative constraint to be separated */
9077 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9078 SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9079 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9080 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9081 )
9082{
9083 SCIP_CONSDATA* consdata;
9084
9085 int* starttimes; /* stores when each job is starting */
9086 int* endtimes; /* stores when each job ends */
9087 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9088 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9089
9090 int nvars; /* number of activities for this constraint */
9091 int freecapacity; /* remaining capacity */
9092 int curtime; /* point in time which we are just checking */
9093 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9094
9095 int hmin;
9096 int hmax;
9097 int j;
9098
9099 assert(scip != NULL);
9100 assert(cons != NULL);
9101
9102 consdata = SCIPconsGetData(cons);
9103 assert(consdata != NULL);
9104
9105 nvars = consdata->nvars;
9106
9107 /* if no activities are associated with this cumulative then this constraint is redundant */
9108 if( nvars <= 1 )
9109 return SCIP_OKAY;
9110
9111 assert(consdata->vars != NULL);
9112
9113 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9114 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9115 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9116 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9117
9118 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9119 SCIPconsGetName(cons), nvars);
9120
9121 /* create event point arrays */
9122 createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9123
9124 /* now nvars might be smaller than before! */
9125
9126 endindex = 0;
9127 freecapacity = consdata->capacity;
9128 hmin = consdata->hmin;
9129 hmax = consdata->hmax;
9130
9131 /* check each startpoint of a job whether the capacity is kept or not */
9132 for( j = 0; j < nvars && !(*cutoff); ++j )
9133 {
9134 curtime = starttimes[j];
9135
9136 if( curtime >= hmax )
9137 break;
9138
9139 /* remove the capacity requirements for all job which start at the curtime */
9140 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9141
9142 /* add the capacity requirments for all job which end at the curtime */
9143 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9144
9145 assert(freecapacity <= consdata->capacity);
9146 assert(endindex <= nvars);
9147
9148 /* endindex - points to the next job which will finish */
9149 /* j - points to the last job that has been released */
9150
9151 /* if free capacity is smaller than zero, then add rows to the LP */
9152 if( freecapacity < 0 && curtime >= hmin)
9153 {
9154 /* create capacity restriction row for current event point */
9155 SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9156 *separated = TRUE;
9157 }
9158 } /*lint --e{850}*/
9159
9160 /* free all buffer arrays */
9161 SCIPfreeBufferArray(scip, &endindices);
9162 SCIPfreeBufferArray(scip, &startindices);
9163 SCIPfreeBufferArray(scip, &endtimes);
9164 SCIPfreeBufferArray(scip, &starttimes);
9165
9166 return SCIP_OKAY;
9167}
9168
9169/**@} */
9170
9171
9172/**@name Presolving
9173 *
9174 * @{
9175 */
9176
9177#ifndef NDEBUG
9178/** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9179 * correct
9180 */
9181static
9183 SCIP* scip, /**< SCIP data structure */
9184 SCIP_CONS* cons /**< constraint to be checked */
9185 )
9186{
9187 SCIP_CONSDATA* consdata;
9188 int capacity;
9189 int nvars;
9190 int j;
9191
9192 assert(scip != NULL);
9193 assert(cons != NULL);
9194
9195 consdata = SCIPconsGetData(cons);
9196 assert(consdata != NULL);
9197
9198 nvars = consdata->nvars;
9199
9200 /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9201 if( nvars <= 1 )
9202 return TRUE;
9203
9204 assert(consdata->vars != NULL);
9205 capacity = consdata->capacity;
9206
9207 /* check each activity: if demand is larger than capacity the problem is infeasible */
9208 for ( j = 0; j < nvars; ++j )
9209 {
9210 if( consdata->demands[j] > capacity )
9211 return FALSE;
9212 }
9213
9214 return TRUE;
9215}
9216#endif
9217
9218/** delete constraint if it consists of at most one job
9219 *
9220 * @todo this method needs to be adjusted w.r.t. effective horizon
9221 */
9222static
9224 SCIP* scip, /**< SCIP data structure */
9225 SCIP_CONS* cons, /**< constraint to propagate */
9226 int* ndelconss, /**< pointer to store the number of deleted constraints */
9227 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9228 )
9229{
9230 SCIP_CONSDATA* consdata;
9231
9232 assert(scip != NULL);
9233 assert(cons != NULL);
9234
9235 consdata = SCIPconsGetData(cons);
9236 assert(consdata != NULL);
9237
9238 if( consdata->nvars == 0 )
9239 {
9240 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9241
9242 SCIP_CALL( SCIPdelCons(scip, cons) );
9243 (*ndelconss)++;
9244 }
9245 else if( consdata->nvars == 1 )
9246 {
9247 if( consdata->demands[0] > consdata->capacity )
9248 (*cutoff) = TRUE;
9249 else
9250 {
9251 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9252
9253 SCIP_CALL( SCIPdelCons(scip, cons) );
9254 (*ndelconss)++;
9255 }
9256 }
9257
9258 return SCIP_OKAY;
9259}
9260
9261/** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9262 * this is done in the SCIP_DECL_CONSINITPRE() callback
9263 */
9264static
9266 SCIP* scip, /**< SCIP data structure */
9267 SCIP_CONS* cons /**< constraint to propagate */
9268 )
9269{
9270 SCIP_CONSDATA* consdata;
9271 SCIP_VAR* var;
9272 int demand;
9273 int duration;
9274 int hmin;
9275 int hmax;
9276 int est;
9277 int lct;
9278 int j;
9279
9280 assert(scip != NULL);
9281 assert(cons != NULL);
9282
9283 consdata = SCIPconsGetData(cons);
9284 assert(consdata != NULL);
9285
9286 hmin = consdata->hmin;
9287 hmax = consdata->hmax;
9288
9289 SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9290 SCIPconsGetName(cons), hmin, hmax);
9291
9292 for( j = consdata->nvars-1; j >= 0; --j )
9293 {
9294 var = consdata->vars[j];
9295 demand = consdata->demands[j];
9296 duration = consdata->durations[j];
9297
9298 /* earliest completion time (ect) and latest start time (lst) */
9300 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9301
9302 if( demand == 0 || duration == 0 )
9303 {
9304 /* jobs with zero demand or zero duration can be removed */
9305 SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9306 SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9307
9308 /* remove variable form constraint */
9309 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9310 }
9311 else if( est >= hmax || lct <= hmin )
9312 {
9313 SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9314 SCIPvarGetName(var), est, lct - duration, duration);
9315
9316 /* delete variable at the given position */
9317 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9318
9319 /* for the statistic we count the number of jobs which are irrelevant */
9321 }
9322 }
9323
9324 return SCIP_OKAY;
9325}
9326
9327/** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9328static
9330 SCIP* scip, /**< SCIP data structure */
9331 SCIP_CONSDATA* consdata, /**< constraint data */
9332 int pos, /**< position of job in the consdata */
9333 int* nchgbds, /**< pointer to store the number of changed bounds */
9334 int* naddconss, /**< pointer to store the number of added constraints */
9335 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9336 )
9337{
9338 SCIP_VAR* var;
9339 SCIP_Bool tightened;
9340 int duration;
9341 int ect;
9342 int lst;
9343
9344 assert(scip != NULL);
9345
9346 /* zero energy jobs should be removed already */
9347 assert(consdata->durations[pos] > 0);
9348 assert(consdata->demands[pos] > 0);
9349
9350 var = consdata->vars[pos];
9351 assert(var != NULL);
9352 duration = consdata->durations[pos];
9353
9354 /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9355 SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9356 SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9357
9358 /* earliest completion time (ect) and latest start time (lst) */
9359 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9361
9362 /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9363 if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9364 return SCIP_OKAY;
9365
9366 if( ect > consdata->hmin && lst < consdata->hmax )
9367 {
9368 /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9369 *cutoff = TRUE;
9370 }
9371 else if( lst < consdata->hmax )
9372 {
9373 /* move the latest start time of this job in such a way that it finishes before or at hmin */
9374 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9375 assert(tightened);
9376 assert(!(*cutoff));
9377 (*nchgbds)++;
9378 }
9379 else if( ect > consdata->hmin )
9380 {
9381 /* move the earliest start time of this job in such a way that it starts after or at hmax */
9382 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9383 assert(tightened);
9384 assert(!(*cutoff));
9385 (*nchgbds)++;
9386 }
9387 else
9388 {
9389 /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9390 * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9391 *
9392 * (var <= hmin - duration) /\ (var >= hmax)
9393 */
9394 SCIP_CONS* cons;
9395
9396 SCIP_VAR* vartuple[2];
9397 SCIP_BOUNDTYPE boundtypetuple[2];
9398 SCIP_Real boundtuple[2];
9399
9400 char name[SCIP_MAXSTRLEN];
9401 int leftbound;
9402 int rightbound;
9403
9404 leftbound = consdata->hmin - duration;
9405 rightbound = consdata->hmax;
9406
9407 /* allocate temporary memory for arrays */
9408 vartuple[0] = var;
9409 vartuple[1] = var;
9410 boundtuple[0] = (SCIP_Real)leftbound;
9411 boundtuple[1] = (SCIP_Real)rightbound;
9412 boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9413 boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9414
9415 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9416 SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9417
9418 /* create and add bounddisjunction constraint */
9419 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9420 TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9421
9423
9424 /* add and release the new constraint */
9425 SCIP_CALL( SCIPaddCons(scip, cons) );
9426 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9427 (*naddconss)++;
9428 }
9429
9430 return SCIP_OKAY;
9431}
9432
9433/** try to removed over sizeed jobs (the demand is larger than the capacity) */
9434static
9436 SCIP* scip, /**< SCIP data structure */
9437 SCIP_CONS* cons, /**< constraint */
9438 int* nchgbds, /**< pointer to store the number of changed bounds */
9439 int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9440 int* naddconss, /**< pointer to store the number of added constraints */
9441 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9442 )
9443{
9444 SCIP_CONSDATA* consdata;
9445 int capacity;
9446 int j;
9447
9448 consdata = SCIPconsGetData(cons);
9449 assert(consdata != NULL);
9450
9451 /* if a cutoff was already detected just return */
9452 if( *cutoff )
9453 return SCIP_OKAY;
9454
9455 capacity = consdata->capacity;
9456
9457 for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9458 {
9459 if( consdata->demands[j] > capacity )
9460 {
9461 SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9462
9463 /* remove variable form constraint */
9464 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9465 (*nchgcoefs)++;
9466 }
9467 }
9468
9469 SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9470
9471 return SCIP_OKAY;
9472}
9473
9474/** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9475static
9477 SCIP* scip, /**< SCIP data structure */
9478 SCIP_VAR* var, /**< integer variable to fix */
9479 SCIP_Bool uplock, /**< has thet start time variable a up lock */
9480 int* nfixedvars /**< pointer to store the number fixed variables */
9481 )
9482{
9483 SCIP_Bool infeasible;
9484 SCIP_Bool tightened;
9485 SCIP_Bool roundable;
9486
9487 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9488 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9489 */
9491 return SCIP_OKAY;
9492
9493 /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9494 * handler is the only one locking that variable up
9495 */
9496 assert(uplock == TRUE || uplock == FALSE);
9497 assert((int)TRUE == 1); /*lint !e506*/
9498 assert((int)FALSE == 0); /*lint !e506*/
9499
9500 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9501 return SCIP_OKAY;
9502
9503 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9504
9505 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9506 * (the transformed problem is always a minimization problem)
9507 */
9508 if( !roundable )
9509 return SCIP_OKAY;
9510
9511 SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9513
9514 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9515 assert(!infeasible);
9516
9517 if( tightened )
9518 {
9519 SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9520 (*nfixedvars)++;
9521 }
9522
9523 return SCIP_OKAY;
9524}
9525
9526/** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9527static
9529 SCIP* scip, /**< SCIP data structure */
9530 SCIP_VAR* var, /**< integer variable to fix */
9531 SCIP_Bool downlock, /**< has the variable a down lock */
9532 int* nfixedvars /**< pointer to store the number fixed variables */
9533 )
9534{
9535 SCIP_Bool infeasible;
9536 SCIP_Bool tightened;
9537 SCIP_Bool roundable;
9538
9539 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9540 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9541 */
9543 return SCIP_OKAY;
9544
9545 /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9546 * handler is the only one locking that variable down
9547 */
9548 assert(downlock == TRUE || downlock == FALSE);
9549 assert((int)TRUE == 1); /*lint !e506*/
9550 assert((int)FALSE == 0); /*lint !e506*/
9551
9552 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9553 return SCIP_OKAY;
9554
9555 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9556
9557 /* is it possible, to round variable down w.r.t. objective function? */
9558 if( !roundable )
9559 return SCIP_OKAY;
9560
9561 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9562 assert(!infeasible);
9563
9564 if( tightened )
9565 {
9566 SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9567 (*nfixedvars)++;
9568 }
9569
9570 return SCIP_OKAY;
9571}
9572
9573/** normalize cumulative condition */
9574static
9576 SCIP* scip, /**< SCIP data structure */
9577 int nvars, /**< number of start time variables (activities) */
9578 int* demands, /**< array of demands */
9579 int* capacity, /**< pointer to store the changed cumulative capacity */
9580 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9581 int* nchgsides /**< pointer to count number of side changes */
9582 )
9583{ /*lint --e{715}*/
9584 SCIP_Longint gcd;
9585 int mindemand1;
9586 int mindemand2;
9587 int v;
9588
9589 if( *capacity == 1 || nvars <= 1 )
9590 return;
9591
9592 assert(demands[nvars-1] <= *capacity);
9593 assert(demands[nvars-2] <= *capacity);
9594
9595 gcd = (SCIP_Longint)demands[nvars-1];
9596 mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9597 mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9598
9599 for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9600 {
9601 assert(mindemand1 <= mindemand2);
9602 assert(demands[v] <= *capacity);
9603
9604 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9605
9606 if( mindemand1 > demands[v] )
9607 {
9608 mindemand2 = mindemand1;
9609 mindemand1 = demands[v];
9610 }
9611 else if( mindemand2 > demands[v] )
9612 mindemand2 = demands[v];
9613 }
9614
9615 if( mindemand1 + mindemand2 > *capacity )
9616 {
9617 SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9618
9619 for( v = 0; v < nvars; ++v )
9620 demands[v] = 1;
9621
9622 (*capacity) = 1;
9623
9624 (*nchgcoefs) += nvars;
9625 (*nchgsides)++;
9626 }
9627 else if( gcd >= 2 )
9628 {
9629 SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9630
9631 for( v = 0; v < nvars; ++v )
9632 demands[v] /= (int) gcd;
9633
9634 (*capacity) /= (int) gcd;
9635
9636 (*nchgcoefs) += nvars;
9637 (*nchgsides)++;
9638 }
9639}
9640
9641/** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9642 * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9643 * capacity since in that case none of the jobs can run in parallel
9644 */
9645static
9647 SCIP* scip, /**< SCIP data structure */
9648 SCIP_CONS* cons, /**< cumulative constraint */
9649 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9650 int* nchgsides /**< pointer to count number of side changes */
9651 )
9652{
9653 SCIP_CONSDATA* consdata;
9654 int capacity;
9655
9656 assert(nchgcoefs != NULL);
9657 assert(nchgsides != NULL);
9658 assert(!SCIPconsIsModifiable(cons));
9659
9660 consdata = SCIPconsGetData(cons);
9661 assert(consdata != NULL);
9662
9663 if( consdata->normalized )
9664 return;
9665
9666 capacity = consdata->capacity;
9667
9668 /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9669
9670 normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9671
9672 consdata->normalized = TRUE;
9673
9674 if( capacity > consdata->capacity )
9675 consdata->varbounds = FALSE;
9676}
9677
9678/** computes for the given cumulative condition the effective horizon */
9679static
9681 SCIP* scip, /**< SCIP data structure */
9682 int nvars, /**< number of variables (jobs) */
9683 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9684 int* durations, /**< array containing corresponding durations */
9685 int* demands, /**< array containing corresponding demands */
9686 int capacity, /**< available cumulative capacity */
9687 int* hmin, /**< pointer to store the left bound of the effective horizon */
9688 int* hmax, /**< pointer to store the right bound of the effective horizon */
9689 int* split /**< point were the cumulative condition can be split */
9690 )
9691{
9692 SCIP_PROFILE* profile;
9693
9694 /* create empty resource profile with infinity resource capacity */
9695 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9696
9697 /* create worst case resource profile */
9698 SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9699
9700 /* print resource profile in if SCIP_DEBUG is defined */
9702
9703 /* computes the first time point where the resource capacity can be violated */
9704 (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9705
9706 /* computes the first time point where the resource capacity is satisfied for sure */
9707 (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9708
9709 (*split) = (*hmax);
9710
9711 if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9712 {
9713 int* timepoints;
9714 int* loads;
9715 int ntimepoints;
9716 int t;
9717
9718 /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9719 * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9720 * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9721 * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9722 * explain the certain "old" bound changes
9723 */
9724
9725 /* search for time points */
9726 ntimepoints = SCIPprofileGetNTimepoints(profile);
9727 timepoints = SCIPprofileGetTimepoints(profile);
9728 loads = SCIPprofileGetLoads(profile);
9729
9730 /* check if there exist a time point within the effective horizon [hmin,hmax) such that the capacity is not exceed w.r.t. worst case profile */
9731 for( t = 0; t < ntimepoints; ++t )
9732 {
9733 /* ignore all time points before the effective horizon */
9734 if( timepoints[t] <= *hmin )
9735 continue;
9736
9737 /* ignore all time points after the effective horizon */
9738 if( timepoints[t] >= *hmax )
9739 break;
9740
9741 /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9742 * can split the cumulative constraint into two cumulative constraints
9743 */
9744 if( loads[t] <= capacity )
9745 {
9746 (*split) = timepoints[t];
9747 break;
9748 }
9749 }
9750 }
9751
9752 /* free worst case profile */
9753 SCIPprofileFree(&profile);
9754
9755 return SCIP_OKAY;
9756}
9757
9758/** creates and adds a cumulative constraint */
9759static
9761 SCIP* scip, /**< SCIP data structure */
9762 const char* name, /**< name of constraint */
9763 int nvars, /**< number of variables (jobs) */
9764 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9765 int* durations, /**< array containing corresponding durations */
9766 int* demands, /**< array containing corresponding demands */
9767 int capacity, /**< available cumulative capacity */
9768 int hmin, /**< left bound of time axis to be considered (including hmin) */
9769 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9770 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9771 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9772 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9773 * Usually set to TRUE. */
9774 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9775 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9776 SCIP_Bool check, /**< should the constraint be checked for feasibility?
9777 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9778 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9779 * Usually set to TRUE. */
9780 SCIP_Bool local, /**< is constraint only valid locally?
9781 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9782 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9783 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9784 * adds coefficients to this constraint. */
9785 SCIP_Bool dynamic, /**< is constraint subject to aging?
9786 * Usually set to FALSE. Set to TRUE for own cuts which
9787 * are seperated as constraints. */
9788 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9789 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9790 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9791 * if it may be moved to a more global node?
9792 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9793 )
9794{
9795 SCIP_CONS* cons;
9796
9797 /* creates cumulative constraint and adds it to problem */
9798 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9799 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9800
9801 /* adjust the effective time horizon of the new constraint */
9802 SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9803 SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9804
9805 /* add and release new cumulative constraint */
9806 SCIP_CALL( SCIPaddCons(scip, cons) );
9807 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9808
9809 return SCIP_OKAY;
9810}
9811
9812/** computes the effective horizon and checks if the constraint can be decompsed */
9813static
9815 SCIP* scip, /**< SCIP data structure */
9816 SCIP_CONS* cons, /**< cumulative constraint */
9817 int* ndelconss, /**< pointer to store the number of deleted constraints */
9818 int* naddconss, /**< pointer to store the number of added constraints */
9819 int* nchgsides /**< pointer to store the number of changed sides */
9820 )
9821{
9822 SCIP_CONSDATA* consdata;
9823 int hmin;
9824 int hmax;
9825 int split;
9826
9827 consdata = SCIPconsGetData(cons);
9828 assert(consdata != NULL);
9829
9830 if( consdata->nvars <= 1 )
9831 return SCIP_OKAY;
9832
9833 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9834 consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9835
9836 /* check if this time point improves the effective horizon */
9837 if( consdata->hmin < hmin )
9838 {
9839 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9840
9841 consdata->hmin = hmin;
9842 (*nchgsides)++;
9843 }
9844
9845 /* check if this time point improves the effective horizon */
9846 if( consdata->hmax > hmax )
9847 {
9848 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9849 consdata->hmax = hmax;
9850 (*nchgsides)++;
9851 }
9852
9853 /* check if the constraint is redundant */
9854 if( consdata->hmax <= consdata->hmin )
9855 {
9856 SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9857 SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9858
9859 SCIP_CALL( SCIPdelCons(scip, cons) );
9860 (*ndelconss)++;
9861 }
9862 else if( consdata->hmin < split && split < consdata->hmax )
9863 {
9864 char name[SCIP_MAXSTRLEN];
9865 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9866
9867 SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9868 SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9869
9870 assert(split < consdata->hmax);
9871
9872 /* creates cumulative constraint and adds it to problem */
9873 SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9874 consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9877
9878 /* adjust the effective time horizon of the constraint */
9879 consdata->hmax = split;
9880
9881 assert(consdata->hmin < consdata->hmax);
9882
9883 /* for the statistic we count the number of time we decompose a cumulative constraint */
9885 (*naddconss)++;
9886 }
9887
9888 return SCIP_OKAY;
9889}
9890
9891
9892/** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9893 *
9894 * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9895 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9896 *
9897 * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9898 * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9899 * down-lock of the corresponding start time variable can be removed.
9900 *
9901 * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9902 * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9903 * negative, than the job can be dual fixed to its earlier start time (est).
9904 *
9905 * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9906 * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9907 * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9908 *
9909 * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9910 * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9911 * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9912 * form variable domain is dual feasible.
9913 *
9914 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9915 * the cumulative condition; The deletion has to be done later.
9916 */
9917static
9919 SCIP* scip, /**< SCIP data structure */
9920 int nvars, /**< number of start time variables (activities) */
9921 SCIP_VAR** vars, /**< array of start time variables */
9922 int* durations, /**< array of durations */
9923 int hmin, /**< left bound of time axis to be considered (including hmin) */
9924 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9925 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9926 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9927 SCIP_CONS* cons, /**< underlying constraint, or NULL */
9928 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9929 int* nfixedvars, /**< pointer to store the number of fixed variables */
9930 int* nchgsides, /**< pointer to store the number of changed sides */
9931 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9932 )
9933{
9934 SCIP_Real* downimpllbs;
9935 SCIP_Real* downimplubs;
9936 SCIP_Real* downproplbs;
9937 SCIP_Real* downpropubs;
9938 SCIP_Real* upimpllbs;
9939 SCIP_Real* upimplubs;
9940 SCIP_Real* upproplbs;
9941 SCIP_Real* uppropubs;
9942
9943 int firstminect;
9944 int secondminect;
9945 int v;
9946
9947 /* get temporary memory for storing probing results needed for step (4) and (5) */
9948 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9949 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9950 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9951 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9952 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9953 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9954 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9955 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9956
9957 assert(scip != NULL);
9958 assert(nvars > 1);
9959 assert(cons != NULL);
9960
9961 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9962
9963 firstminect = INT_MAX;
9964 secondminect = INT_MAX;
9965
9966 /* compute the two smallest earlier completion times; which are needed for step (5) */
9967 for( v = 0; v < nvars; ++v )
9968 {
9969 int ect;
9970
9971 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9972
9973 if( ect < firstminect )
9974 {
9975 secondminect = firstminect;
9976 firstminect = ect;
9977 }
9978 else if( ect < secondminect )
9979 secondminect = ect;
9980 }
9981
9982 /* loop over all jobs and check if one of the 5 reductions can be applied */
9983 for( v = 0; v < nvars; ++v )
9984 {
9985 SCIP_VAR* var;
9986 int duration;
9987
9988 int alternativelb;
9989 int minect;
9990 int est;
9991 int ect;
9992 int lst;
9993 int lct;
9994
9995 var = vars[v];
9996 assert(var != NULL);
9997
9998 duration = durations[v];
9999 assert(duration > 0);
10000
10001 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10002 * time (lct)
10003 */
10005 ect = est + duration;
10007 lct = lst + duration;
10008
10009 /* compute the earliest completion time of all remaining jobs */
10010 if( ect == firstminect )
10011 minect = secondminect;
10012 else
10013 minect = firstminect;
10014
10015 /* compute potential alternative lower bound (step (4) and (5)) */
10016 alternativelb = MAX(hmin+1, minect);
10017 alternativelb = MIN(alternativelb, hmax);
10018
10019 if( lct <= hmin )
10020 {
10021 /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
10022 * cumulative condition
10023 */
10024 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10025 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10026
10027 /* mark variable to be irrelevant */
10028 irrelevants[v] = TRUE;
10029
10030 /* for the statistic we count the number of jobs which are irrelevant */
10032 }
10033 else if( lst <= hmin && SCIPconsIsChecked(cons) )
10034 {
10035 /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
10036 * so the down lock can be omitted
10037 */
10038
10039 assert(downlocks != NULL);
10040 assert(uplocks != NULL);
10041
10042 if( !uplocks[v] )
10043 {
10044 /* the variables has no up lock and we can also remove the down lock;
10045 * => lst <= hmin and ect >= hmax
10046 * => remove job and reduce capacity by the demand of that job
10047 *
10048 * We mark the job to be deletable. The removement together with the capacity reducion is done later
10049 */
10050
10051 SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10052 SCIPvarGetName(var), ect - duration, lst, duration);
10053
10054 /* mark variable to be irrelevant */
10055 irrelevants[v] = TRUE;
10056
10057 /* for the statistic we count the number of jobs which always run during the effective horizon */
10059 }
10060
10061 if( downlocks[v] )
10062 {
10063 SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10064 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10065
10066 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10067 downlocks[v] = FALSE;
10068 (*nchgsides)++;
10069
10070 /* for the statistic we count the number of removed locks */
10072 }
10073 }
10074 else if( ect <= hmin )
10075 {
10076 /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10077 * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10078 * removed form the cumulative condition after it was fixed to its earliest start time
10079 */
10080
10081 /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10082 * bound;
10083 */
10084 if( downlocks != NULL && SCIPconsIsChecked(cons) )
10085 {
10086 /* fix integer start time variable if possible to it lower bound */
10087 SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10088 }
10089
10090 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10091 {
10092 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10093 SCIPvarGetName(var), ect - duration, lst, duration);
10094
10095 /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10096 assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10097
10098 /* mark variable to be irrelevant */
10099 irrelevants[v] = TRUE;
10100
10101 /* for the statistic we count the number of jobs which are dual fixed */
10103 }
10104 }
10105 else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10106 {
10107 assert(downlocks != NULL);
10108
10109 /* check step (4) and (5) */
10110
10111 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10112 * is in favor of rounding the variable down
10113 */
10114 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10115 {
10116 SCIP_Bool roundable;
10117
10118 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10119
10120 if( roundable )
10121 {
10122 if( alternativelb > lst )
10123 {
10124 SCIP_Bool infeasible;
10125 SCIP_Bool fixed;
10126
10127 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10128 assert(!infeasible);
10129 assert(fixed);
10130
10131 (*nfixedvars)++;
10132
10133 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10134 * constraints
10135 */
10137 }
10138 else
10139 {
10140 SCIP_Bool success;
10141
10142 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10143 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10144 * infeasible we can apply the dual reduction; otherwise we do nothing
10145 */
10146 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10147 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10148 nfixedvars, &success, cutoff) );
10149
10150 if( success )
10151 {
10153 }
10154 }
10155 }
10156 }
10157 }
10158
10159 SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10160 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10161 }
10162
10163 /* free temporary memory */
10164 SCIPfreeBufferArray(scip, &uppropubs);
10165 SCIPfreeBufferArray(scip, &upproplbs);
10166 SCIPfreeBufferArray(scip, &upimplubs);
10167 SCIPfreeBufferArray(scip, &upimpllbs);
10168 SCIPfreeBufferArray(scip, &downpropubs);
10169 SCIPfreeBufferArray(scip, &downproplbs);
10170 SCIPfreeBufferArray(scip, &downimplubs);
10171 SCIPfreeBufferArray(scip, &downimpllbs);
10172
10173 return SCIP_OKAY;
10174}
10175
10176/** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10177 *
10178 * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10179 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10180 *
10181 * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10182 * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10183 * up-lock of the corresponding start time variable can be removed.
10184 *
10185 * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10186 * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10187 * positive, than the job can be dual fixed to its latest start time (lst).
10188 *
10189 * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10190 * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10191 * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10192 * of the corresponding job).
10193
10194 * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10195 * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10196 * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10197 * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10198 *
10199 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10200 * the cumulative condition; The deletion has to be done later.
10201 */
10202static
10204 SCIP* scip, /**< SCIP data structure */
10205 int nvars, /**< number of start time variables (activities) */
10206 SCIP_VAR** vars, /**< array of start time variables */
10207 int* durations, /**< array of durations */
10208 int hmin, /**< left bound of time axis to be considered (including hmin) */
10209 int hmax, /**< right bound of time axis to be considered (not including hmax) */
10210 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10211 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10212 SCIP_CONS* cons, /**< underlying constraint, or NULL */
10213 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10214 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10215 int* nchgsides, /**< pointer to store the number of changed sides */
10216 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10217 )
10218{
10219 SCIP_Real* downimpllbs;
10220 SCIP_Real* downimplubs;
10221 SCIP_Real* downproplbs;
10222 SCIP_Real* downpropubs;
10223 SCIP_Real* upimpllbs;
10224 SCIP_Real* upimplubs;
10225 SCIP_Real* upproplbs;
10226 SCIP_Real* uppropubs;
10227
10228 int firstmaxlst;
10229 int secondmaxlst;
10230 int v;
10231
10232 /* get temporary memory for storing probing results needed for step (4) and (5) */
10233 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10234 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10235 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10236 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10237 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10238 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10239 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10240 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10241
10242 assert(scip != NULL);
10243 assert(nvars > 1);
10244 assert(cons != NULL);
10245
10246 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10247
10248 firstmaxlst = INT_MIN;
10249 secondmaxlst = INT_MIN;
10250
10251 /* compute the two largest latest start times; which are needed for step (5) */
10252 for( v = 0; v < nvars; ++v )
10253 {
10254 int lst;
10255
10257
10258 if( lst > firstmaxlst )
10259 {
10260 secondmaxlst = firstmaxlst;
10261 firstmaxlst = lst;
10262 }
10263 else if( lst > secondmaxlst )
10264 secondmaxlst = lst;
10265 }
10266
10267 /* loop over all jobs and check if one of the 5 reductions can be applied */
10268 for( v = 0; v < nvars; ++v )
10269 {
10270 SCIP_VAR* var;
10271 int duration;
10272
10273 int alternativeub;
10274 int maxlst;
10275 int est;
10276 int ect;
10277 int lst;
10278
10279 var = vars[v];
10280 assert(var != NULL);
10281
10282 duration = durations[v];
10283 assert(duration > 0);
10284
10285 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10286 * time (lct)
10287 */
10289 ect = est + duration;
10291
10292 /* compute the latest start time of all remaining jobs */
10293 if( lst == firstmaxlst )
10294 maxlst = secondmaxlst;
10295 else
10296 maxlst = firstmaxlst;
10297
10298 /* compute potential alternative upper bound (step (4) and (5)) */
10299 alternativeub = MIN(hmax - 1, maxlst) - duration;
10300 alternativeub = MAX(alternativeub, hmin);
10301
10302 if( est >= hmax )
10303 {
10304 /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10305 * cumulative condition
10306 */
10307 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10308 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10309
10310 /* mark variable to be irrelevant */
10311 irrelevants[v] = TRUE;
10312
10313 /* for the statistic we count the number of jobs which are irrelevant */
10315 }
10316 else if( ect >= hmax && SCIPconsIsChecked(cons) )
10317 {
10318 assert(downlocks != NULL);
10319 assert(uplocks != NULL);
10320
10321 /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10322 * so the up lock can be omitted
10323 */
10324
10325 if( !downlocks[v] )
10326 {
10327 /* the variables has no down lock and we can also remove the up lock;
10328 * => lst <= hmin and ect >= hmax
10329 * => remove job and reduce capacity by the demand of that job
10330 */
10331 SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10332 SCIPvarGetName(var), est, lst, duration);
10333
10334 /* mark variable to be irrelevant */
10335 irrelevants[v] = TRUE;
10336
10337 /* for the statistic we count the number of jobs which always run during the effective horizon */
10339 }
10340
10341 if( uplocks[v] )
10342 {
10343 SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10344 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10345
10346 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10347 uplocks[v] = FALSE;
10348 (*nchgsides)++;
10349
10350 /* for the statistic we count the number of removed locks */
10352 }
10353 }
10354 else if( lst >= hmax )
10355 {
10356 /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10357 * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10358 * removed form the cumulative condition after it was fixed to its latest start time
10359 */
10360
10361 /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10362 * bound
10363 */
10364 if( uplocks != NULL && SCIPconsIsChecked(cons) )
10365 {
10366 /* fix integer start time variable if possible to its upper bound */
10367 SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10368 }
10369
10370 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10371 {
10372 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10373 SCIPvarGetName(var), est, lst, duration);
10374
10375 /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10376 assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10377
10378 /* mark variable to be irrelevant */
10379 irrelevants[v] = TRUE;
10380
10381 /* for the statistic we count the number of jobs which are dual fixed */
10383 }
10384 }
10385 else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10386 {
10387 assert(uplocks != NULL);
10388
10389 /* check step (4) and (5) */
10390
10391 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10392 * is in favor of rounding the variable down
10393 */
10394 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10395 {
10396 SCIP_Bool roundable;
10397
10398 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10399
10400 if( roundable )
10401 {
10402 if( alternativeub < est )
10403 {
10404 SCIP_Bool infeasible;
10405 SCIP_Bool fixed;
10406
10407 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10408 assert(!infeasible);
10409 assert(fixed);
10410
10411 (*nfixedvars)++;
10412
10413 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10414 * constraints
10415 */
10417 }
10418 else
10419 {
10420 SCIP_Bool success;
10421
10422 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10423 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10424 * in infeasible we can apply the dual reduction; otherwise we do nothing
10425 */
10426 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10427 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10428 nfixedvars, &success, cutoff) );
10429
10430 if( success )
10431 {
10433 }
10434 }
10435 }
10436 }
10437 }
10438 }
10439
10440 /* free temporary memory */
10441 SCIPfreeBufferArray(scip, &uppropubs);
10442 SCIPfreeBufferArray(scip, &upproplbs);
10443 SCIPfreeBufferArray(scip, &upimplubs);
10444 SCIPfreeBufferArray(scip, &upimpllbs);
10445 SCIPfreeBufferArray(scip, &downpropubs);
10446 SCIPfreeBufferArray(scip, &downproplbs);
10447 SCIPfreeBufferArray(scip, &downimplubs);
10448 SCIPfreeBufferArray(scip, &downimpllbs);
10449
10450 return SCIP_OKAY;
10451}
10452
10453/** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10454static
10456 SCIP* scip, /**< SCIP data structure */
10457 SCIP_CONS* cons, /**< cumulative constraint */
10458 int* nfixedvars, /**< pointer to store the number of fixed variables */
10459 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10460 int* nchgsides, /**< pointer to store the number of changed sides */
10461 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10462 )
10463{
10464 SCIP_CONSDATA* consdata;
10465 SCIP_Bool* irrelevants;
10466 int nvars;
10467 int v;
10468
10469 assert(scip != NULL);
10470 assert(cons != NULL);
10471 assert(!(*cutoff));
10472
10473 consdata = SCIPconsGetData(cons);
10474 assert(consdata != NULL);
10475
10476 nvars = consdata->nvars;
10477
10478 if( nvars <= 1 )
10479 return SCIP_OKAY;
10480
10481 SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10482 BMSclearMemoryArray(irrelevants, nvars);
10483
10484 /* presolve constraint form the earlier start time point of view */
10485 SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10486 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10487 irrelevants, nfixedvars, nchgsides, cutoff) );
10488
10489 /* presolve constraint form the latest completion time point of view */
10490 SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10491 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10492 irrelevants, nfixedvars, nchgsides, cutoff) );
10493
10494 /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10495 * order to ensure a correct behaviour
10496 */
10497 for( v = nvars-1; v >= 0; --v )
10498 {
10499 if( irrelevants[v] )
10500 {
10501 SCIP_VAR* var;
10502 int ect;
10503 int lst;
10504
10505 var = consdata->vars[v];
10506 assert(var != NULL);
10507
10508 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10510
10511 /* check if the jobs runs completely during the effective horizon */
10512 if( lst <= consdata->hmin && ect >= consdata->hmax )
10513 {
10514 if( consdata->capacity < consdata->demands[v] )
10515 {
10516 *cutoff = TRUE;
10517 break;
10518 }
10519
10520 consdata->capacity -= consdata->demands[v];
10521 consdata->varbounds = FALSE;
10522 }
10523
10524 SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10525 (*nchgcoefs)++;
10526 }
10527 }
10528
10529 SCIPfreeBufferArray(scip, &irrelevants);
10530
10531 return SCIP_OKAY;
10532}
10533
10534/** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10535static
10537 SCIP* scip, /**< SCIP data structure */
10538 SCIP_CONSDATA* consdata, /**< constraint data */
10539 int* startindices, /**< permutation with rspect to the start times */
10540 int curtime, /**< current point in time */
10541 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10542 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10543 SCIP_Longint** demands, /**< pointer to array storing the demands */
10544 int* ndemands /**< pointer to store the number of different demands */
10545 )
10546{
10547 int startindex;
10548 int ncountedvars;
10549
10550 assert(demands != NULL);
10551 assert(ndemands != NULL);
10552
10553 ncountedvars = 0;
10554 startindex = nstarted - 1;
10555
10556 *ndemands = 0;
10557
10558 /* search for the (nstarted - nfinished) jobs which are active at curtime */
10559 while( nstarted - nfinished > ncountedvars )
10560 {
10561 SCIP_VAR* var;
10562 int endtime;
10563 int varidx;
10564
10565 /* collect job information */
10566 varidx = startindices[startindex];
10567 assert(varidx >= 0 && varidx < consdata->nvars);
10568
10569 var = consdata->vars[varidx];
10570 assert(var != NULL);
10571
10572 endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10573
10574 /* check the end time of this job is larger than the curtime; in this case the job is still running */
10575 if( endtime > curtime )
10576 {
10577 if( consdata->demands[varidx] < consdata->capacity )
10578 {
10579 (*demands)[*ndemands] = consdata->demands[varidx];
10580 (*ndemands)++;
10581 }
10582 ncountedvars++;
10583 }
10584
10585 startindex--;
10586 }
10587}
10588
10589/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10590 * constraint
10591 */
10592static
10594 SCIP* scip, /**< SCIP data structure */
10595 SCIP_CONS* cons, /**< constraint to be checked */
10596 int* startindices, /**< permutation with rspect to the start times */
10597 int curtime, /**< current point in time */
10598 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10599 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10600 int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10601 )
10602{
10603 SCIP_CONSDATA* consdata;
10604 SCIP_Longint* demands;
10605 SCIP_Real* profits;
10606 int* items;
10607 int ndemands;
10608 SCIP_Bool success;
10609 SCIP_Real solval;
10610 int j;
10611 assert(nstarted > nfinished);
10612
10613 consdata = SCIPconsGetData(cons);
10614 assert(consdata != NULL);
10615 assert(consdata->nvars > 0);
10616 assert(consdata->capacity > 0);
10617
10618 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10619 ndemands = 0;
10620
10621 /* get demand array to initialize knapsack problem */
10622 collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10623
10624 /* create array for profits */
10625 SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10626 SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10627 for( j = 0; j < ndemands; ++j )
10628 {
10629 profits[j] = (SCIP_Real) demands[j];
10630 items[j] = j;/* this is only a dummy value*/
10631 }
10632
10633 /* solve knapsack problem and get maximum capacity usage <= capacity */
10634 SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10635 items, NULL, NULL, NULL, NULL, &solval, &success) );
10636
10637 assert(SCIPisFeasIntegral(scip, solval));
10638
10639 /* store result */
10640 *bestcapacity = SCIPconvertRealToInt(scip, solval);
10641
10642 SCIPfreeBufferArray(scip, &items);
10643 SCIPfreeBufferArray(scip, &profits);
10644 SCIPfreeBufferArray(scip, &demands);
10645
10646 return SCIP_OKAY;
10647}
10648
10649/** try to tighten the capacity
10650 * -- using DP for knapsack, we find the maximum possible capacity usage
10651 * -- neglects hmin and hmax, such that it is also able to check solutions globally
10652 */
10653static
10655 SCIP* scip, /**< SCIP data structure */
10656 SCIP_CONS* cons, /**< cumulative constraint */
10657 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10658 int* nchgsides /**< pointer to store the number of changed sides */
10659 )
10660{
10661 SCIP_CONSDATA* consdata;
10662 int* starttimes; /* stores when each job is starting */
10663 int* endtimes; /* stores when each job ends */
10664 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10665 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10666
10667 int nvars; /* number of activities for this constraint */
10668 int freecapacity; /* remaining capacity */
10669 int curtime; /* point in time which we are just checking */
10670 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10671
10672 int bestcapacity;
10673
10674 int j;
10675
10676 assert(scip != NULL);
10677 assert(cons != NULL);
10678 assert(nchgsides != NULL);
10679
10680 consdata = SCIPconsGetData(cons);
10681 assert(consdata != NULL);
10682
10683 nvars = consdata->nvars;
10684
10685 /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10686 if( nvars <= 1 || consdata->capacity <= 1 )
10687 return SCIP_OKAY;
10688
10689 assert(consdata->vars != NULL);
10690
10691 SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10692 SCIPconsGetName(cons), consdata->capacity);
10693
10694 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10695 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10696 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10697 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10698
10699 /* create event point arrays */
10700 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10701 starttimes, endtimes, startindices, endindices, FALSE);
10702
10703 bestcapacity = 1;
10704 endindex = 0;
10705 freecapacity = consdata->capacity;
10706
10707 /* check each startpoint of a job whether the capacity is kept or not */
10708 for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10709 {
10710 curtime = starttimes[j];
10711 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10712
10713 /* remove the capacity requirments for all job which start at the curtime */
10714 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10715
10716 /* add the capacity requirments for all job which end at the curtime */
10717 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10718
10719 assert(freecapacity <= consdata->capacity);
10720 assert(endindex <= nvars);
10721
10722 /* endindex - points to the next job which will finish */
10723 /* j - points to the last job that has been released */
10724
10725 /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10726 if( freecapacity < 0 )
10727 {
10728 int newcapacity;
10729
10730 newcapacity = 1;
10731
10732 /* get best possible upper bound on capacity usage */
10733 SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10734
10735 /* update bestcapacity */
10736 bestcapacity = MAX(bestcapacity, newcapacity);
10737 SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10738 }
10739
10740 /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10741 if( freecapacity > 0 && freecapacity != consdata->capacity )
10742 {
10743 bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10744 SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10745 }
10746
10747 /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10748 if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10749 {
10750 /* if demands[startindices[j]] == cap then exactly that job is running */
10751 SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10752 bestcapacity = consdata->capacity;
10753 break;
10754 }
10755 } /*lint --e{850}*/
10756
10757 /* free all buffer arrays */
10758 SCIPfreeBufferArray(scip, &endindices);
10759 SCIPfreeBufferArray(scip, &startindices);
10760 SCIPfreeBufferArray(scip, &endtimes);
10761 SCIPfreeBufferArray(scip, &starttimes);
10762
10763 /* check whether capacity can be tightened and whether demands need to be adjusted */
10764 if( bestcapacity < consdata->capacity )
10765 {
10766 SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10767
10768 SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10769 SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10770
10771 for( j = 0; j < nvars; ++j )
10772 {
10773 if( consdata->demands[j] == consdata->capacity )
10774 {
10775 consdata->demands[j] = bestcapacity;
10776 (*nchgcoefs)++;
10777 }
10778 }
10779
10780 consdata->capacity = bestcapacity;
10781 (*nchgsides)++;
10782
10783 SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10784
10785 consdata->varbounds = FALSE;
10786 }
10787
10788 return SCIP_OKAY;
10789}
10790
10791/** tries to change coefficients:
10792 * demand_j < cap && all other parallel jobs in conflict
10793 * ==> set demand_j := cap
10794 */
10795static
10797 SCIP* scip, /**< SCIP data structure */
10798 SCIP_CONS* cons, /**< cumulative constraint */
10799 int* nchgcoefs /**< pointer to count total number of changed coefficients */
10800 )
10801{
10802 SCIP_CONSDATA* consdata;
10803 int nvars;
10804 int j;
10805 int oldnchgcoefs;
10806 int mindemand;
10807
10808 assert(scip != NULL);
10809 assert(cons != NULL);
10810 assert(nchgcoefs != NULL);
10811
10812 /* get constraint data for some parameter testings only! */
10813 consdata = SCIPconsGetData(cons);
10814 assert(consdata != NULL);
10815
10816 nvars = consdata->nvars;
10817 oldnchgcoefs = *nchgcoefs;
10818
10819 if( nvars <= 0 )
10820 return SCIP_OKAY;
10821
10822 /* PRE1:
10823 * check all jobs j whether: r_j + r_min > capacity holds
10824 * if so: adjust r_j to capacity
10825 */
10826 mindemand = consdata->demands[0];
10827 for( j = 0; j < nvars; ++j )
10828 {
10829 mindemand = MIN(mindemand, consdata->demands[j]);
10830 }
10831
10832 /*check each job */
10833 for( j = 0; j < nvars; ++j )
10834 {
10835 if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10836 {
10837 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10838 consdata->demands[j], consdata->capacity);
10839 consdata->demands[j] = consdata->capacity;
10840 (*nchgcoefs)++;
10841 }
10842 }
10843
10844 /* PRE2:
10845 * check for each job (with d_j < cap)
10846 * whether it is disjunctive to all others over the time horizon
10847 */
10848 for( j = 0; j < nvars; ++j )
10849 {
10850 SCIP_Bool chgcoef;
10851 int est_j;
10852 int lct_j;
10853 int i;
10854
10855 assert(consdata->demands[j] <= consdata->capacity);
10856
10857 if( consdata->demands[j] == consdata->capacity )
10858 continue;
10859
10860 chgcoef = TRUE;
10861
10862 est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10863 lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10864
10865 for( i = 0; i < nvars; ++i )
10866 {
10867 int est_i;
10868 int lct_i;
10869
10870 if( i == j )
10871 continue;
10872
10873 est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10874 lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10875
10876 if( est_i >= lct_j || est_j >= lct_i )
10877 continue;
10878
10879 if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10880 {
10881 chgcoef = FALSE;
10882 break;
10883 }
10884 }
10885
10886 if( chgcoef )
10887 {
10888 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10889 consdata->demands[j], consdata->capacity);
10890 consdata->demands[j] = consdata->capacity;
10891 (*nchgcoefs)++;
10892 }
10893 }
10894
10895 if( (*nchgcoefs) > oldnchgcoefs )
10896 {
10897 SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10898 (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10899 }
10900
10901 return SCIP_OKAY;
10902}
10903
10904#if 0
10905/** try to reformulate constraint by replacing certain jobs */
10906static
10907SCIP_RETCODE reformulateCons(
10908 SCIP* scip, /**< SCIP data structure */
10909 SCIP_CONS* cons, /**< cumulative constraint */
10910 int* naggrvars /**< pointer to store the number of aggregated variables */
10911 )
10912{
10913 SCIP_CONSDATA* consdata;
10914 int hmin;
10915 int hmax;
10916 int nvars;
10917 int v;
10918
10919 consdata = SCIPconsGetData(cons);
10920 assert(cons != NULL);
10921
10922 nvars = consdata->nvars;
10923 assert(nvars > 1);
10924
10925 hmin = consdata->hmin;
10926 hmax = consdata->hmax;
10927 assert(hmin < hmax);
10928
10929 for( v = 0; v < nvars; ++v )
10930 {
10931 SCIP_VAR* var;
10932 int duration;
10933 int est;
10934 int ect;
10935 int lst;
10936 int lct;
10937
10938 var = consdata->vars[v];
10939 assert(var != NULL);
10940
10941 duration = consdata->durations[v];
10942
10944 ect = est + duration;
10946 lct = lst + duration;
10947
10948 /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10949 assert(lst > hmin || ect < hmax);
10950
10951 if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10952 {
10953 SCIP_VAR* aggrvar;
10954 char name[SCIP_MAXSTRLEN];
10955 SCIP_Bool infeasible;
10956 SCIP_Bool redundant;
10957 SCIP_Bool aggregated;
10958 int shift;
10959
10960 shift = est - (hmin - lct + MIN(hmin, ect));
10961 assert(shift > 0);
10962 lst = hmin;
10963 duration = hmin - lct;
10964
10965 SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10966 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10967
10968 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10969 SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10971 SCIP_CALL( SCIPaddVar(scip, var) );
10972 SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10973
10974 assert(!infeasible);
10975 assert(!redundant);
10976 assert(aggregated);
10977
10978 /* replace variable */
10979 consdata->durations[v] = duration;
10980 consdata->vars[v] = aggrvar;
10981
10982 /* remove and add locks */
10983 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10984 SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10985
10986 SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10987
10988 (*naggrvars)++;
10989 }
10990 }
10991
10992 return SCIP_OKAY;
10993}
10994#endif
10995
10996/** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10997static
10999 SCIP* scip, /**< SCIP data structure */
11000 SCIP_CONS* cons, /**< cumulative constraint */
11001 int* naddconss /**< pointer to store the number of added constraints */
11002 )
11003{
11004 SCIP_CONSDATA* consdata;
11005 SCIP_VAR** vars;
11006 int* durations;
11007 int* demands;
11008 int capacity;
11009 int halfcapacity;
11010 int mindemand;
11011 int nvars;
11012 int v;
11013
11014 consdata = SCIPconsGetData(cons);
11015 assert(consdata != NULL);
11016
11017 capacity = consdata->capacity;
11018
11019 if( capacity == 1 )
11020 return SCIP_OKAY;
11021
11022 SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
11023 SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
11024 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
11025
11026 halfcapacity = capacity / 2;
11027 mindemand = consdata->capacity;
11028 nvars = 0;
11029
11030 /* collect all jobs with demand larger than half of the capacity */
11031 for( v = 0; v < consdata->nvars; ++v )
11032 {
11033 if( consdata->demands[v] > halfcapacity )
11034 {
11035 vars[nvars] = consdata->vars[v];
11036 demands[nvars] = 1;
11037 durations[nvars] = consdata->durations[v];
11038 nvars++;
11039
11040 mindemand = MIN(mindemand, consdata->demands[v]);
11041 }
11042 }
11043
11044 if( nvars > 0 )
11045 {
11046 /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11047 * job is still to large to be scheduled in parallel
11048 */
11049 for( v = 0; v < consdata->nvars; ++v )
11050 {
11051 if( consdata->demands[v] > halfcapacity )
11052 continue;
11053
11054 if( mindemand + consdata->demands[v] > capacity )
11055 {
11056 demands[nvars] = 1;
11057 durations[nvars] = consdata->durations[v];
11058 vars[nvars] = consdata->vars[v];
11059 nvars++;
11060
11061 /* @todo create one cumulative constraint and look for another small demand */
11062 break;
11063 }
11064 }
11065
11066 /* creates cumulative constraint and adds it to problem */
11067 SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11069 (*naddconss)++;
11070 }
11071
11072 SCIPfreeBufferArray(scip, &demands);
11073 SCIPfreeBufferArray(scip, &durations);
11074 SCIPfreeBufferArray(scip, &vars);
11075
11076 return SCIP_OKAY;
11077}
11078
11079/** presolve given constraint */
11080static
11082 SCIP* scip, /**< SCIP data structure */
11083 SCIP_CONS* cons, /**< cumulative constraint */
11084 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11085 SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11086 int* nfixedvars, /**< pointer to store the number of fixed variables */
11087#if 0
11088 int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11089#endif
11090 int* nchgbds, /**< pointer to store the number of changed bounds */
11091 int* ndelconss, /**< pointer to store the number of deleted constraints */
11092 int* naddconss, /**< pointer to store the number of added constraints */
11093 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11094 int* nchgsides, /**< pointer to store the number of changed sides */
11095 SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11096 SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11097 )
11098{
11099 assert(!SCIPconsIsDeleted(cons));
11100
11101 /* only perform dual reductions on model constraints */
11102 if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11103 {
11104 /* computes the effective horizon and checks if the constraint can be decomposed */
11105 SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11106
11107 if( SCIPconsIsDeleted(cons) )
11108 return SCIP_OKAY;
11109
11110 /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11111 * fixings (dual reductions)
11112 */
11113 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11114 {
11115 SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11116
11117 if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11118 return SCIP_OKAY;
11119 }
11120
11121 SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11122
11123 if( *cutoff || SCIPconsIsDeleted(cons) )
11124 return SCIP_OKAY;
11125 }
11126
11127 /* remove jobs which have a demand larger than the capacity */
11128 SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11129 assert((*cutoff) || checkDemands(scip, cons));
11130
11131 if( *cutoff )
11132 return SCIP_OKAY;
11133
11134 if( conshdlrdata->normalize )
11135 {
11136 /* divide demands by their greatest common divisor */
11137 normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11138 }
11139
11140 /* delete constraint with one job */
11141 SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11142
11143 if( *cutoff || SCIPconsIsDeleted(cons) )
11144 return SCIP_OKAY;
11145
11146 if( conshdlrdata->coeftightening )
11147 {
11148 /* try to tighten the capacity */
11149 SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11150
11151 /* try to tighten the coefficients */
11152 SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11153 }
11154
11155 assert(checkDemands(scip, cons) || *cutoff);
11156
11157#if 0
11158 SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11159#endif
11160
11161 return SCIP_OKAY;
11162}
11163
11164/**@name TClique Graph callbacks
11165 *
11166 * @{
11167 */
11168
11169/** tclique graph data */
11170struct TCLIQUE_Graph
11171{
11172 SCIP_VAR** vars; /**< start time variables each of them is a node */
11173 SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11174 SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11175 SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11176 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11177 int* ninarcs; /**< number if in arcs for the precedence graph */
11178 int* noutarcs; /**< number if out arcs for the precedence graph */
11179 int* durations; /**< for each node the duration of the corresponding job */
11180 int nnodes; /**< number of nodes */
11181 int size; /**< size of the array */
11182};
11183
11184/** gets number of nodes in the graph */
11185static
11186TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11187{
11188 assert(tcliquegraph != NULL);
11189
11190 return tcliquegraph->nnodes;
11191}
11192
11193/** gets weight of nodes in the graph */
11194static
11195TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11196{
11197 assert(tcliquegraph != NULL);
11198
11199 return tcliquegraph->weights;
11200}
11201
11202/** returns, whether the edge (node1, node2) is in the graph */
11203static
11204TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11205{
11206 assert(tcliquegraph != NULL);
11207 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11208 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11209
11210 /* check if an arc exits in the precedence graph */
11211 if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11212 return TRUE;
11213
11214 /* check if an edge exits in the non-overlapping graph */
11215 if( tcliquegraph->demandmatrix[node1][node2] )
11216 return TRUE;
11217
11218 return FALSE;
11219}
11220
11221/** selects all nodes from a given set of nodes which are adjacent to a given node
11222 * and returns the number of selected nodes
11223 */
11224static
11225TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11226{
11227 int nadjnodes;
11228 int i;
11229
11230 assert(tcliquegraph != NULL);
11231 assert(0 <= node && node < tcliquegraph->nnodes);
11232 assert(nnodes == 0 || nodes != NULL);
11233 assert(adjnodes != NULL);
11234
11235 nadjnodes = 0;
11236
11237 for( i = 0; i < nnodes; i++ )
11238 {
11239 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11240 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11241 assert(i == 0 || nodes[i-1] < nodes[i]);
11242
11243 /* check if an edge exists */
11244 if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11245 {
11246 /* current node is adjacent to given node */
11247 adjnodes[nadjnodes] = nodes[i];
11248 nadjnodes++;
11249 }
11250 }
11251
11252 return nadjnodes;
11253}
11254
11255/** generates cuts using a clique found by algorithm for maximum weight clique
11256 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11257 */
11258static
11259TCLIQUE_NEWSOL(tcliqueNewsolClique)
11260{ /*lint --e{715}*/
11261 SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11262}
11263
11264/** print the tclique graph */
11265#if 0
11266static
11267void tcliquePrint(
11268 SCIP* scip, /**< SCIP data structure */
11269 TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11270 )
11271{
11272 int nnodes;
11273 int i;
11274 int j;
11275
11276 nnodes = tcliquegraph->nnodes;
11277
11278 for( i = 0; i < nnodes; ++i )
11279 {
11280 for( j = 0; j < nnodes; ++j )
11281 {
11282 SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11283 }
11284 SCIPinfoMessage(scip, NULL, "\n");
11285 }
11286}
11287#endif
11288
11289/** @} */
11290
11291/** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11292 * job corresponding to variable bound variable (vlbvar)
11293 *
11294 * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11295 */
11296static
11298 SCIP* scip, /**< SCIP data structure */
11299 SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11300 SCIP_Real vlbcoef, /**< variable bound coefficient */
11301 SCIP_Real vlbconst, /**< variable bound constant */
11302 int duration /**< duration of the variable bound variable */
11303 )
11304{
11305 if( SCIPisEQ(scip, vlbcoef, 1.0) )
11306 {
11307 if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11308 {
11309 /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11310 return TRUE;
11311 }
11312 }
11313 else
11314 {
11316
11317 bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11318
11319 if( SCIPisLT(scip, vlbcoef, 1.0) )
11320 {
11321 SCIP_Real ub;
11322
11323 ub = SCIPvarGetUbLocal(vlbvar);
11324
11325 /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11326 if( SCIPisLE(scip, ub, bound) )
11327 return TRUE;
11328 }
11329 else
11330 {
11331 SCIP_Real lb;
11332
11333 assert(SCIPisGT(scip, vlbcoef, 1.0));
11334
11335 lb = SCIPvarGetLbLocal(vlbvar);
11336
11337 /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11338 if( SCIPisGE(scip, lb, bound) )
11339 return TRUE;
11340 }
11341 }
11342
11343 return FALSE;
11344}
11345
11346/** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11347 * job corresponding to variable which is bounded (var)
11348 *
11349 * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11350 */
11351static
11353 SCIP* scip, /**< SCIP data structure */
11354 SCIP_VAR* var, /**< variable which is bound from above */
11355 SCIP_Real vubcoef, /**< variable bound coefficient */
11356 SCIP_Real vubconst, /**< variable bound constant */
11357 int duration /**< duration of the variable which is bounded from above */
11358 )
11359{
11360 SCIP_Real vlbcoef;
11361 SCIP_Real vlbconst;
11362
11363 /* convert the variable upper bound into an variable lower bound */
11364 vlbcoef = 1.0 / vubcoef;
11365 vlbconst = -vubconst / vubcoef;
11366
11367 return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11368}
11369
11370/** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11371 * others an index larger than the number if active variables
11372 */
11373static
11375 SCIP* scip, /**< SCIP data structure */
11376 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11377 SCIP_VAR* var, /**< variable for which we want the index */
11378 int* idx /**< pointer to store the index */
11379 )
11380{
11381 (*idx) = SCIPvarGetProbindex(var);
11382
11383 if( (*idx) == -1 )
11384 {
11385 if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11386 {
11387 (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11388 }
11389 else
11390 {
11391 int pos;
11392 int v;
11393
11394 /**@todo we might want to add the aggregation path to graph */
11395
11396 /* check if we have to realloc memory */
11397 if( tcliquegraph->size == tcliquegraph->nnodes )
11398 {
11399 int size;
11400
11401 size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11402 tcliquegraph->size = size;
11403
11404 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11405 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11406 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11407 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11408 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11409
11410 for( v = 0; v < tcliquegraph->nnodes; ++v )
11411 {
11412 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11413 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11414 }
11415 }
11416 assert(tcliquegraph->nnodes < tcliquegraph->size);
11417
11418 pos = tcliquegraph->nnodes;
11419 assert(pos >= 0);
11420
11421 tcliquegraph->durations[pos] = 0;
11422 tcliquegraph->weights[pos] = 0;
11423 tcliquegraph->vars[pos] = var;
11424
11425 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11426 BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11427
11428 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11429 BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11430
11431 SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11432
11433 tcliquegraph->nnodes++;
11434
11435 for( v = 0; v < tcliquegraph->nnodes; ++v )
11436 {
11437 tcliquegraph->precedencematrix[v][pos] = 0;
11438 tcliquegraph->demandmatrix[v][pos] = 0;
11439 }
11440
11441 (*idx) = tcliquegraph->nnodes;
11442 }
11443 }
11444 else
11445 {
11446 assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11447 }
11448
11449 assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11450
11451 return SCIP_OKAY;
11452}
11453
11454/** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11455 *
11456 * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11457 * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11458 *
11459 * (i) b = 1 and c >= d
11460 * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11461 * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11462 *
11463 */
11464static
11466 SCIP* scip, /**< SCIP data structure */
11467 TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11468 )
11469{
11470 SCIP_VAR** vars;
11471 int nvars;
11472 int v;
11473
11474 vars = SCIPgetVars(scip);
11475 nvars = SCIPgetNVars(scip);
11476
11477 /* try to project each arc of the variable bound graph to precedence condition */
11478 for( v = 0; v < nvars; ++v )
11479 {
11480 SCIP_VAR** vbdvars;
11481 SCIP_VAR* var;
11482 SCIP_Real* vbdcoefs;
11483 SCIP_Real* vbdconsts;
11484 int nvbdvars;
11485 int idx1;
11486 int b;
11487
11488 var = vars[v];
11489 assert(var != NULL);
11490
11491 SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11492 assert(idx1 >= 0);
11493
11494 if( tcliquegraph->durations[idx1] == 0 )
11495 continue;
11496
11497 vbdvars = SCIPvarGetVlbVars(var);
11498 vbdcoefs = SCIPvarGetVlbCoefs(var);
11499 vbdconsts = SCIPvarGetVlbConstants(var);
11500 nvbdvars = SCIPvarGetNVlbs(var);
11501
11502 for( b = 0; b < nvbdvars; ++b )
11503 {
11504 int idx2;
11505
11506 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11507 assert(idx2 >= 0);
11508
11509 if( tcliquegraph->durations[idx2] == 0 )
11510 continue;
11511
11512 if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11513 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11514 }
11515
11516 vbdvars = SCIPvarGetVubVars(var);
11517 vbdcoefs = SCIPvarGetVubCoefs(var);
11518 vbdconsts = SCIPvarGetVubConstants(var);
11519 nvbdvars = SCIPvarGetNVubs(var);
11520
11521 for( b = 0; b < nvbdvars; ++b )
11522 {
11523 int idx2;
11524
11525 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11526 assert(idx2 >= 0);
11527
11528 if( tcliquegraph->durations[idx2] == 0 )
11529 continue;
11530
11531 if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11532 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11533 }
11534
11535 for( b = v+1; b < nvars; ++b )
11536 {
11537 int idx2;
11538
11539 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11540 assert(idx2 >= 0);
11541
11542 if( tcliquegraph->durations[idx2] == 0 )
11543 continue;
11544
11545 /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11546 if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11547 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11548
11549 /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11550 if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11551 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11552 }
11553 }
11554
11555 return SCIP_OKAY;
11556}
11557
11558/** compute the transitive closer of the given graph and the number of in and out arcs */
11559static
11561 SCIP_Bool** adjmatrix, /**< adjacent matrix */
11562 int* ninarcs, /**< array to store the number of in arcs */
11563 int* noutarcs, /**< array to store the number of out arcs */
11564 int nnodes /**< number if nodes */
11565 )
11566{
11567 int i;
11568 int j;
11569 int k;
11570
11571 for( i = 0; i < nnodes; ++i )
11572 {
11573 for( j = 0; j < nnodes; ++j )
11574 {
11575 if( adjmatrix[i][j] )
11576 {
11577 ninarcs[j]++;
11578 noutarcs[i]++;
11579
11580 for( k = 0; k < nnodes; ++k )
11581 {
11582 if( adjmatrix[j][k] )
11583 adjmatrix[i][k] = TRUE;
11584 }
11585 }
11586 }
11587 }
11588}
11589
11590/** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11591static
11593 SCIP* scip, /**< SCIP data structure */
11594 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11595 SCIP_CONS** conss, /**< array of cumulative constraints */
11596 int nconss /**< number of cumulative constraints */
11597 )
11598{
11599 int c;
11600
11601 /* use the cumulative constraints to initialize the none overlapping graph */
11602 for( c = 0; c < nconss; ++c )
11603 {
11604 SCIP_CONSDATA* consdata;
11605 SCIP_VAR** vars;
11606 int* demands;
11607 int capacity;
11608 int nvars;
11609 int i;
11610
11611 consdata = SCIPconsGetData(conss[c]);
11612 assert(consdata != NULL);
11613
11614 vars = consdata->vars;
11615 demands = consdata->demands;
11616
11617 nvars = consdata->nvars;
11618 capacity = consdata->capacity;
11619
11620 SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11621
11622 /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11623 for( i = 0; i < nvars; ++i )
11624 {
11625 int idx1;
11626 int j;
11627
11628 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11629 assert(idx1 >= 0);
11630
11631 if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11632 continue;
11633
11634 for( j = i+1; j < nvars; ++j )
11635 {
11636 assert(consdata->durations[j] > 0);
11637
11638 if( demands[i] + demands[j] > capacity )
11639 {
11640 int idx2;
11641 int est1;
11642 int est2;
11643 int lct1;
11644 int lct2;
11645
11646 /* check if the effective horizon is large enough */
11649
11650 /* at least one of the jobs needs to start at hmin or later */
11651 if( est1 < consdata->hmin && est2 < consdata->hmin )
11652 continue;
11653
11654 lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11655 lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11656
11657 /* at least one of the jobs needs to finish not later then hmin */
11658 if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11659 continue;
11660
11661 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11662 assert(idx2 >= 0);
11663 assert(idx1 != idx2);
11664
11665 if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11666 continue;
11667
11668 SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11669
11670 assert(tcliquegraph->durations[idx1] > 0);
11671 assert(tcliquegraph->durations[idx2] > 0);
11672
11673 tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11674 tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11675 }
11676 }
11677 }
11678 }
11679
11680 return SCIP_OKAY;
11681}
11682
11683/** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11684 * of jobs cannot run in parallel
11685 */
11686static
11688 SCIP* scip, /**< SCIP data structure */
11689 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11690 SCIP_CONS** conss, /**< array of cumulative constraints */
11691 int nconss /**< number of cumulative constraints */
11692 )
11693{
11694 assert(scip != NULL);
11695 assert(tcliquegraph != NULL);
11696
11697 /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11698 SCIP_CALL( projectVbd(scip, tcliquegraph) );
11699
11700 /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11701 transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11702
11703 /* constraints non-overlapping graph */
11704 SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11705
11706 return SCIP_OKAY;
11707}
11708
11709/** create cumulative constraint from conflict set */
11710static
11712 SCIP* scip, /**< SCIP data structure */
11713 const char* name, /**< constraint name */
11714 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11715 int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11716 int ncliquenodes /**< number of nodes in the clique */
11717 )
11718{
11719 SCIP_CONS* cons;
11720 SCIP_VAR** vars;
11721 int* durations;
11722 int* demands;
11723 int v;
11724
11725 SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11726 SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11727 SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11728
11729 SCIPsortInt(cliquenodes, ncliquenodes);
11730
11731 /* collect variables, durations, and demands */
11732 for( v = 0; v < ncliquenodes; ++v )
11733 {
11734 durations[v] = tcliquegraph->durations[cliquenodes[v]];
11735 assert(durations[v] > 0);
11736 demands[v] = 1;
11737 vars[v] = tcliquegraph->vars[cliquenodes[v]];
11738 }
11739
11740 /* create (unary) cumulative constraint */
11741 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11743
11744 SCIP_CALL( SCIPaddCons(scip, cons) );
11745 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11746
11747 /* free buffers */
11748 SCIPfreeBufferArray(scip, &demands);
11749 SCIPfreeBufferArray(scip, &durations);
11750 SCIPfreeBufferArray(scip, &vars);
11751
11752 return SCIP_OKAY;
11753}
11754
11755/** search for cumulative constrainst */
11756static
11758 SCIP* scip, /**< SCIP data structure */
11759 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11760 int* naddconss /**< pointer to store the number of added constraints */
11761 )
11762{
11763 TCLIQUE_STATUS tcliquestatus;
11764 SCIP_Bool* precedencerow;
11765 SCIP_Bool* precedencecol;
11766 SCIP_Bool* demandrow;
11767 SCIP_Bool* demandcol;
11768 SCIP_HASHTABLE* covered;
11769 int* cliquenodes;
11770 int ncliquenodes;
11771 int cliqueweight;
11772 int ntreenodes;
11773 int nnodes;
11774 int nconss;
11775 int v;
11776
11777 nnodes = tcliquegraph->nnodes;
11778 nconss = 0;
11779
11780 /* initialize the weight of each job with its duration */
11781 for( v = 0; v < nnodes; ++v )
11782 {
11783 tcliquegraph->weights[v] = tcliquegraph->durations[v];
11784 }
11785
11786 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11787 SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11788 SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11789 SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11790 SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11791
11792 /* create a hash table to store all start time variables which are already covered by at least one clique */
11794 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11795
11796 /* for each variables/job we are ... */
11797 for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11798 {
11799 char name[SCIP_MAXSTRLEN];
11800 int c;
11801
11802 /* jobs with zero durations are skipped */
11803 if( tcliquegraph->durations[v] == 0 )
11804 continue;
11805
11806 /* check if the start time variable is already covered by at least one clique */
11807 if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11808 continue;
11809
11810 SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11811
11812 /* temporarily remove the connection via the precedence graph */
11813 for( c = 0; c < nnodes; ++c )
11814 {
11815 precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11816 precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11817
11818 demandrow[c] = tcliquegraph->demandmatrix[v][c];
11819 demandcol[c] = tcliquegraph->demandmatrix[c][v];
11820
11821#if 0
11822 if( precedencerow[c] || precedencecol[c] )
11823 {
11824 tcliquegraph->demandmatrix[v][c] = FALSE;
11825 tcliquegraph->demandmatrix[c][v] = FALSE;
11826 }
11827#endif
11828
11829 tcliquegraph->precedencematrix[c][v] = FALSE;
11830 tcliquegraph->precedencematrix[v][c] = FALSE;
11831 }
11832
11833 /* find (heuristically) maximum cliques which includes node v */
11834 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11835 tcliquegraph, tcliqueNewsolClique, NULL,
11836 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11837 10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11838
11839 SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11840
11841 if( ncliquenodes == 1 )
11842 continue;
11843
11844 /* construct constraint name */
11845 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11846
11847 SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11848 nconss++;
11849
11850 /* all start time variable to covered hash table */
11851 for( c = 0; c < ncliquenodes; ++c )
11852 {
11853 SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11854 }
11855
11856 /* copy the precedence relations back */
11857 for( c = 0; c < nnodes; ++c )
11858 {
11859 tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11860 tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11861
11862 tcliquegraph->demandmatrix[v][c] = demandrow[c];
11863 tcliquegraph->demandmatrix[c][v] = demandcol[c];
11864 }
11865 }
11866
11867 SCIPhashtableFree(&covered);
11868
11869 SCIPfreeBufferArray(scip, &demandcol);
11870 SCIPfreeBufferArray(scip, &demandrow);
11871 SCIPfreeBufferArray(scip, &precedencecol);
11872 SCIPfreeBufferArray(scip, &precedencerow);
11873 SCIPfreeBufferArray(scip, &cliquenodes);
11874
11875 (*naddconss) += nconss;
11876
11877 /* for the statistic we count the number added disjunctive constraints */
11878 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11879
11880 return SCIP_OKAY;
11881}
11882
11883/** create precedence constraint (as variable bound constraint */
11884static
11886 SCIP* scip, /**< SCIP data structure */
11887 const char* name, /**< constraint name */
11888 SCIP_VAR* var, /**< variable x that has variable bound */
11889 SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11890 int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11891 )
11892{
11893 SCIP_CONS* cons;
11894
11895 /* create variable bound constraint */
11896 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11898
11900
11901 /* add constraint to problem and release it */
11902 SCIP_CALL( SCIPaddCons(scip, cons) );
11903 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11904
11905 return SCIP_OKAY;
11906}
11907
11908/** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11909static
11911 SCIP* scip, /**< SCIP data structure */
11912 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11913 int source, /**< index of the source node */
11914 int sink, /**< index of the sink node */
11915 int* naddconss /**< pointer to store the number of added constraints */
11916 )
11917{
11918 TCLIQUE_WEIGHT cliqueweight;
11919 TCLIQUE_STATUS tcliquestatus;
11920 SCIP_VAR** vars;
11921 int* cliquenodes;
11922 int nnodes;
11923 int lct;
11924 int est;
11925 int i;
11926
11927 int ntreenodes;
11928 int ncliquenodes;
11929
11930 /* check if source and sink are connencted */
11931 if( !tcliquegraph->precedencematrix[source][sink] )
11932 return SCIP_OKAY;
11933
11934 nnodes = tcliquegraph->nnodes;
11935 vars = tcliquegraph->vars;
11936
11937 /* reset the weights to zero */
11938 BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11939
11940 /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11941 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11942 est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11943
11944 /* weight all jobs which run for sure between source and sink with their duration */
11945 for( i = 0; i < nnodes; ++i )
11946 {
11947 SCIP_VAR* var;
11948 int duration;
11949
11950 var = vars[i];
11951 assert(var != NULL);
11952
11953 duration = tcliquegraph->durations[i];
11954
11955 if( i == source || i == sink )
11956 {
11957 /* source and sink are not weighted */
11958 tcliquegraph->weights[i] = 0;
11959 }
11960 else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11961 {
11962 /* job i runs after source and before sink */
11963 tcliquegraph->weights[i] = duration;
11964 }
11965 else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11966 && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11967 {
11968 /* job i run in between due the bounds of the start time variables */
11969 tcliquegraph->weights[i] = duration;
11970 }
11971 else
11972 tcliquegraph->weights[i] = 0;
11973 }
11974
11975 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11976
11977 /* find (heuristically) maximum cliques */
11978 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11979 tcliquegraph, tcliqueNewsolClique, NULL,
11980 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11981 10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11982
11983 if( ncliquenodes > 1 )
11984 {
11985 char name[SCIP_MAXSTRLEN];
11986 int distance;
11987
11988 /* construct constraint name */
11989 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11990
11991 /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11992 * duration of the source job
11993 */
11994 distance = cliqueweight + tcliquegraph->durations[source];
11995
11996 SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11997 (*naddconss)++;
11998 }
11999
12000 SCIPfreeBufferArray(scip, &cliquenodes);
12001
12002 return SCIP_OKAY;
12003}
12004
12005/** search for precedence constraints
12006 *
12007 * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
12008 * corresponding two jobs
12009 */
12010static
12012 SCIP* scip, /**< SCIP data structure */
12013 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
12014 int* naddconss /**< pointer to store the number of added constraints */
12015 )
12016{
12017 int* sources;
12018 int* sinks;
12019 int nconss;
12020 int nnodes;
12021 int nsources;
12022 int nsinks;
12023 int i;
12024
12025 nnodes = tcliquegraph->nnodes;
12026 nconss = 0;
12027
12028 nsources = 0;
12029 nsinks = 0;
12030
12033
12034 /* first collect all sources and sinks */
12035 for( i = 0; i < nnodes; ++i )
12036 {
12037 if( tcliquegraph->ninarcs[i] == 0 )
12038 {
12039 sources[nsources] = i;
12040 nsources++;
12041 }
12042
12043 if( tcliquegraph->ninarcs[i] == 0 )
12044 {
12045 sinks[nsinks] = i;
12046 nsinks++;
12047 }
12048 }
12049
12050 /* compute for each node a minimum distance to each sources and each sink */
12051 for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12052 {
12053 int j;
12054
12055 for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12056 {
12057 SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12058 }
12059
12060 for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12061 {
12062 SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12063 }
12064 }
12065
12066 (*naddconss) += nconss;
12067
12068 /* for the statistic we count the number added variable constraints */
12069 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12070
12071 SCIPfreeBufferArray(scip, &sinks);
12072 SCIPfreeBufferArray(scip, &sources);
12073
12074 return SCIP_OKAY;
12075}
12076
12077/** initialize the assumed durations for each variable */
12078static
12080 SCIP* scip, /**< SCIP data structure */
12081 TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12082 SCIP_CONS** conss, /**< cumulative constraints */
12083 int nconss /**< number of cumulative constraints */
12084 )
12085{
12086 int c;
12087
12088 /* use the cumulative structure to define the duration we are using for each job */
12089 for( c = 0; c < nconss; ++c )
12090 {
12091 SCIP_CONSDATA* consdata;
12092 SCIP_VAR** vars;
12093 int nvars;
12094 int v;
12095
12096 consdata = SCIPconsGetData(conss[c]);
12097 assert(consdata != NULL);
12098
12099 vars = consdata->vars;
12100 nvars = consdata->nvars;
12101
12102 for( v = 0; v < nvars; ++v )
12103 {
12104 int idx;
12105
12106 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12107 assert(idx >= 0);
12108
12109 /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12110 * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12111 * general this is not the case. Therefore, the question would be which duration should be used?
12112 */
12113 tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12114 assert(tcliquegraph->durations[idx] > 0);
12115 }
12116 }
12117
12118 return SCIP_OKAY;
12119}
12120
12121/** create tclique graph */
12122static
12124 SCIP* scip, /**< SCIP data structure */
12125 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12126 )
12127{
12128 SCIP_VAR** vars;
12129 SCIP_HASHMAP* varmap;
12130 SCIP_Bool** precedencematrix;
12131 SCIP_Bool** demandmatrix;
12132 int* ninarcs;
12133 int* noutarcs;
12134 int* durations;
12135 int* weights;
12136 int nvars;
12137 int v;
12138
12139 vars = SCIPgetVars(scip);
12140 nvars = SCIPgetNVars(scip);
12141
12142 /* allocate memory for the tclique graph data structure */
12143 SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12144
12145 /* create the variable mapping hash map */
12146 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12147
12148 /* each active variables get a node in the graph */
12149 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12150
12151 /* allocate memory for the projected variables bound graph and the none overlapping graph */
12152 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12153 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12154
12155 /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12156 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12157 BMSclearMemoryArray(weights, nvars);
12158
12159 /* array to store the number of in arc of the precedence graph */
12160 SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12161 BMSclearMemoryArray(ninarcs, nvars);
12162
12163 /* array to store the number of out arc of the precedence graph */
12164 SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12165 BMSclearMemoryArray(noutarcs, nvars);
12166
12167 /* array to store the used duration for each node */
12168 SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12169 BMSclearMemoryArray(durations, nvars);
12170
12171 for( v = 0; v < nvars; ++v )
12172 {
12173 SCIP_VAR* var;
12174
12175 var = vars[v];
12176 assert(var != NULL);
12177
12178 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12179 BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12180
12181 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12182 BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12183
12184 /* insert all active variables into the garph */
12185 assert(SCIPvarGetProbindex(var) == v);
12186 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12187 }
12188
12189 (*tcliquegraph)->nnodes = nvars;
12190 (*tcliquegraph)->varmap = varmap;
12191 (*tcliquegraph)->precedencematrix = precedencematrix;
12192 (*tcliquegraph)->demandmatrix = demandmatrix;
12193 (*tcliquegraph)->weights = weights;
12194 (*tcliquegraph)->ninarcs = ninarcs;
12195 (*tcliquegraph)->noutarcs = noutarcs;
12196 (*tcliquegraph)->durations = durations;
12197 (*tcliquegraph)->size = nvars;
12198
12199 return SCIP_OKAY;
12200}
12201
12202/** frees the tclique graph */
12203static
12205 SCIP* scip, /**< SCIP data structure */
12206 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12207 )
12208{
12209 int v;
12210
12211 for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12212 {
12213 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12214 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12215 }
12216
12217 SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12218 SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12219 SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12220 SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12221 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12222 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12223 SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12224 SCIPhashmapFree(&(*tcliquegraph)->varmap);
12225
12226 SCIPfreeBuffer(scip, tcliquegraph);
12227}
12228
12229/** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12230 * constrains (disjunctive constraint)
12231 */
12232static
12234 SCIP* scip, /**< SCIP data structure */
12235 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12236 SCIP_CONS** conss, /**< array of cumulative constraints */
12237 int nconss, /**< number of cumulative constraints */
12238 int* naddconss /**< pointer to store the number of added constraints */
12239 )
12240{
12241 TCLIQUE_GRAPH* tcliquegraph;
12242
12243 /* create tclique graph */
12244 SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12245
12246 /* define for each job a duration */
12247 SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12248
12249 /* constuct incompatibility graph */
12250 SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12251
12252 /* search for new precedence constraints */
12253 if( conshdlrdata->detectvarbounds )
12254 {
12255 SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12256 }
12257
12258 /* search for new cumulative constraints */
12259 if( conshdlrdata->detectdisjunctive )
12260 {
12261 SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12262 }
12263
12264 /* free tclique graph data structure */
12265 freeTcliqueGraph(scip, &tcliquegraph);
12266
12267 return SCIP_OKAY;
12268}
12269
12270/** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12271static
12273 SCIP_CONSDATA* consdata /**< cumulative constraint data */
12274 )
12275{
12276 SCIP_VAR** vars;
12277 int nvars;
12278 int v;
12279
12280 if( consdata->validsignature )
12281 return;
12282
12283 vars = consdata->vars;
12284 nvars = consdata->nvars;
12285
12286 for( v = 0; v < nvars; ++v )
12287 {
12288 consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12289 }
12290
12291 consdata->validsignature = TRUE;
12292}
12293
12294/** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12295static
12297{ /*lint --e{715}*/
12298 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12299
12300 assert(consdata != NULL);
12301 assert(0 <= ind1 && ind1 < consdata->nvars);
12302 assert(0 <= ind2 && ind2 < consdata->nvars);
12303
12304 return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12305}
12306
12307/** run a pairwise comparison */
12308static
12310 SCIP* scip, /**< SCIP data structure */
12311 SCIP_CONS** conss, /**< array of cumulative constraints */
12312 int nconss, /**< number of cumulative constraints */
12313 int* ndelconss /**< pointer to store the number of deletedconstraints */
12314 )
12315{
12316 int i;
12317 int j;
12318
12319 for( i = 0; i < nconss; ++i )
12320 {
12321 SCIP_CONSDATA* consdata0;
12322 SCIP_CONS* cons0;
12323
12324 cons0 = conss[i];
12325 assert(cons0 != NULL);
12326
12327 consdata0 = SCIPconsGetData(cons0);
12328 assert(consdata0 != NULL);
12329
12330 consdataCalcSignature(consdata0);
12331 assert(consdata0->validsignature);
12332
12333 for( j = i+1; j < nconss; ++j )
12334 {
12335 SCIP_CONSDATA* consdata1;
12336 SCIP_CONS* cons1;
12337
12338 cons1 = conss[j];
12339 assert(cons1 != NULL);
12340
12341 consdata1 = SCIPconsGetData(cons1);
12342 assert(consdata1 != NULL);
12343
12344 if( consdata0->capacity != consdata1->capacity )
12345 continue;
12346
12347 consdataCalcSignature(consdata1);
12348 assert(consdata1->validsignature);
12349
12350 if( (consdata1->signature & (~consdata0->signature)) == 0 )
12351 {
12352 SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12353 SCIPswapPointers((void**)&cons0, (void**)&cons1);
12354 assert((consdata0->signature & (~consdata1->signature)) == 0);
12355 }
12356
12357 if( (consdata0->signature & (~consdata1->signature)) == 0 )
12358 {
12359 int* perm0;
12360 int* perm1;
12361 int v0;
12362 int v1;
12363
12364 if( consdata0->nvars > consdata1->nvars )
12365 continue;
12366
12367 if( consdata0->hmin < consdata1->hmin )
12368 continue;
12369
12370 if( consdata0->hmax > consdata1->hmax )
12371 continue;
12372
12373 SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12374 SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12375
12376 /* call sorting method */
12377 SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12378 SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12379
12380 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12381 {
12382 SCIP_VAR* var0;
12383 SCIP_VAR* var1;
12384 int idx0;
12385 int idx1;
12386 int comp;
12387
12388 idx0 = perm0[v0];
12389 idx1 = perm1[v1];
12390
12391 var0 = consdata0->vars[idx0];
12392
12393 var1 = consdata1->vars[idx1];
12394
12395 comp = SCIPvarCompare(var0, var1);
12396
12397 if( comp == 0 )
12398 {
12399 int duration0;
12400 int duration1;
12401 int demand0;
12402 int demand1;
12403
12404 demand0 = consdata0->demands[idx0];
12405 duration0 = consdata0->durations[idx0];
12406
12407 demand1 = consdata1->demands[idx1];
12408 duration1 = consdata1->durations[idx1];
12409
12410 if( demand0 != demand1 )
12411 break;
12412
12413 if( duration0 != duration1 )
12414 break;
12415
12416 v0++;
12417 v1++;
12418 }
12419 else if( comp > 0 )
12420 v1++;
12421 else
12422 break;
12423 }
12424
12425 if( v0 == consdata0->nvars )
12426 {
12427 if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12428 {
12429 initializeLocks(consdata1, TRUE);
12430 }
12431
12432 /* coverity[swapped_arguments] */
12433 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12434
12435 SCIP_CALL( SCIPdelCons(scip, cons0) );
12436 (*ndelconss)++;
12437 }
12438
12439 SCIPfreeBufferArray(scip, &perm1);
12440 SCIPfreeBufferArray(scip, &perm0);
12441 }
12442 }
12443 }
12444
12445 return SCIP_OKAY;
12446}
12447
12448/** strengthen the variable bounds using the cumulative condition */
12449static
12451 SCIP* scip, /**< SCIP data structure */
12452 SCIP_CONS* cons, /**< constraint to propagate */
12453 int* nchgbds, /**< pointer to store the number of changed bounds */
12454 int* naddconss /**< pointer to store the number of added constraints */
12455 )
12456{
12457 SCIP_CONSDATA* consdata;
12458 SCIP_VAR** vars;
12459 int* durations;
12460 int* demands;
12461 int capacity;
12462 int nvars;
12463 int nconss;
12464 int i;
12465
12466 consdata = SCIPconsGetData(cons);
12467 assert(consdata != NULL);
12468
12469 /* check if the variable bounds got already strengthen by the cumulative constraint */
12470 if( consdata->varbounds )
12471 return SCIP_OKAY;
12472
12473 vars = consdata->vars;
12474 durations = consdata->durations;
12475 demands = consdata->demands;
12476 capacity = consdata->capacity;
12477 nvars = consdata->nvars;
12478
12479 nconss = 0;
12480
12481 for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12482 {
12483 SCIP_VAR** vbdvars;
12484 SCIP_VAR* var;
12485 SCIP_Real* vbdcoefs;
12486 SCIP_Real* vbdconsts;
12487 int nvbdvars;
12488 int b;
12489 int j;
12490
12491 var = consdata->vars[i];
12492 assert(var != NULL);
12493
12494 vbdvars = SCIPvarGetVlbVars(var);
12495 vbdcoefs = SCIPvarGetVlbCoefs(var);
12496 vbdconsts = SCIPvarGetVlbConstants(var);
12497 nvbdvars = SCIPvarGetNVlbs(var);
12498
12499 for( b = 0; b < nvbdvars; ++b )
12500 {
12501 if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12502 {
12503 if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12504 {
12505 for( j = 0; j < nvars; ++j )
12506 {
12507 if( vars[j] == vbdvars[b] )
12508 break;
12509 }
12510 if( j == nvars )
12511 continue;
12512
12513 if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12514 {
12515 SCIP_Bool infeasible;
12516 char name[SCIP_MAXSTRLEN];
12517 int nlocalbdchgs;
12518
12519 SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12520
12521 /* construct constraint name */
12522 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12523
12524 SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12525 nconss++;
12526
12527 SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12528 assert(!infeasible);
12529
12530 (*nchgbds) += nlocalbdchgs;
12531 }
12532 }
12533 }
12534 }
12535 }
12536
12537 (*naddconss) += nconss;
12538
12539 consdata->varbounds = TRUE;
12540
12541 return SCIP_OKAY;
12542}
12543
12544/** helper function to enforce constraints */
12545static
12547 SCIP* scip, /**< SCIP data structure */
12548 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12549 SCIP_CONS** conss, /**< constraints to process */
12550 int nconss, /**< number of constraints */
12551 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12552 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12553 SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12554 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12555 )
12556{
12557 SCIP_CONSHDLRDATA* conshdlrdata;
12558
12559 assert(conshdlr != NULL);
12560 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12561 assert(nconss == 0 || conss != NULL);
12562 assert(result != NULL);
12563
12564 if( solinfeasible )
12565 {
12566 *result = SCIP_INFEASIBLE;
12567 return SCIP_OKAY;
12568 }
12569
12570 SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12571 sol == NULL ? "LP" : "relaxation");
12572
12573 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12574 assert(conshdlrdata != NULL);
12575
12576 (*result) = SCIP_FEASIBLE;
12577
12578 if( conshdlrdata->usebinvars )
12579 {
12580 SCIP_Bool separated;
12581 SCIP_Bool cutoff;
12582 int c;
12583
12584 separated = FALSE;
12585
12586 /* first check if a constraints is violated */
12587 for( c = 0; c < nusefulconss; ++c )
12588 {
12589 SCIP_CONS* cons;
12590 SCIP_Bool violated;
12591
12592 cons = conss[c];
12593 assert(cons != NULL);
12594
12595 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12596
12597 if( !violated )
12598 continue;
12599
12600 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12601 if ( cutoff )
12602 {
12603 *result = SCIP_CUTOFF;
12604 return SCIP_OKAY;
12605 }
12606 }
12607
12608 for( ; c < nconss && !separated; ++c )
12609 {
12610 SCIP_CONS* cons;
12611 SCIP_Bool violated;
12612
12613 cons = conss[c];
12614 assert(cons != NULL);
12615
12616 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12617
12618 if( !violated )
12619 continue;
12620
12621 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12622 if ( cutoff )
12623 {
12624 *result = SCIP_CUTOFF;
12625 return SCIP_OKAY;
12626 }
12627 }
12628
12629 if( separated )
12630 (*result) = SCIP_SEPARATED;
12631 }
12632 else
12633 {
12634 SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12635 }
12636
12637 return SCIP_OKAY;
12638}
12639
12640/**@} */
12641
12642
12643/**@name Callback methods of constraint handler
12644 *
12645 * @{
12646 */
12647
12648/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12649static
12650SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12651{ /*lint --e{715}*/
12652 assert(scip != NULL);
12653 assert(conshdlr != NULL);
12654 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12655
12656 /* call inclusion method of constraint handler */
12658
12660
12661 *valid = TRUE;
12662
12663 return SCIP_OKAY;
12664}
12665
12666/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12667static
12668SCIP_DECL_CONSFREE(consFreeCumulative)
12669{ /*lint --e{715}*/
12670 SCIP_CONSHDLRDATA* conshdlrdata;
12671
12672 assert(conshdlr != NULL);
12673 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12674
12675 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12676 assert(conshdlrdata != NULL);
12677
12678#ifdef SCIP_STATISTIC
12679 if( !conshdlrdata->iscopy )
12680 {
12681 /* statisitc output if SCIP_STATISTIC is defined */
12682 SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12683 conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12684 SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12685 conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12686 SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12687 conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12688 }
12689#endif
12690
12691 conshdlrdataFree(scip, &conshdlrdata);
12692
12693 SCIPconshdlrSetData(conshdlr, NULL);
12694
12695 return SCIP_OKAY;
12696}
12697
12698
12699/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12700static
12701SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12702{ /*lint --e{715}*/
12703 SCIP_CONSHDLRDATA* conshdlrdata;
12704 int c;
12705
12706 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12707 assert(conshdlrdata != NULL);
12708
12709 conshdlrdata->detectedredundant = FALSE;
12710
12711 for( c = 0; c < nconss; ++c )
12712 {
12713 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12714 * hmax)
12715 */
12716 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12717 }
12718
12719 return SCIP_OKAY;
12720}
12721
12722
12723/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12724#ifdef SCIP_STATISTIC
12725static
12726SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12727{ /*lint --e{715}*/
12728 SCIP_CONSHDLRDATA* conshdlrdata;
12729 int c;
12730
12731 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12732 assert(conshdlrdata != NULL);
12733
12734 for( c = 0; c < nconss; ++c )
12735 {
12736 SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12737
12738#if 0
12740#endif
12741 }
12742
12743 if( !conshdlrdata->iscopy )
12744 {
12745 SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12746 SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12747 SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12748 SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12749 SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12750 SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12751 SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12752 SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12753 SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12754 }
12755
12756 return SCIP_OKAY;
12757}
12758#endif
12759
12760
12761/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12762static
12763SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12764{ /*lint --e{715}*/
12765 SCIP_CONSDATA* consdata;
12766 int c;
12767
12768 assert(conshdlr != NULL);
12769 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12770
12771 /* release the rows of all constraints */
12772 for( c = 0; c < nconss; ++c )
12773 {
12774 consdata = SCIPconsGetData(conss[c]);
12775 assert(consdata != NULL);
12776
12777 /* free rows */
12778 SCIP_CALL( consdataFreeRows(scip, &consdata) );
12779 }
12780
12781 return SCIP_OKAY;
12782}
12783
12784/** frees specific constraint data */
12785static
12786SCIP_DECL_CONSDELETE(consDeleteCumulative)
12787{ /*lint --e{715}*/
12788 assert(conshdlr != NULL);
12789 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12790 assert(consdata != NULL );
12791 assert(*consdata != NULL );
12792
12793 /* if constraint belongs to transformed problem space, drop bound change events on variables */
12794 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12795 {
12796 SCIP_CONSHDLRDATA* conshdlrdata;
12797
12798 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12799 assert(conshdlrdata != NULL);
12800
12801 SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12802 }
12803
12804 /* free cumulative constraint data */
12805 SCIP_CALL( consdataFree(scip, consdata) );
12806
12807 return SCIP_OKAY;
12808}
12809
12810/** transforms constraint data into data belonging to the transformed problem */
12811static
12812SCIP_DECL_CONSTRANS(consTransCumulative)
12813{ /*lint --e{715}*/
12814 SCIP_CONSHDLRDATA* conshdlrdata;
12815 SCIP_CONSDATA* sourcedata;
12816 SCIP_CONSDATA* targetdata;
12817
12818 assert(conshdlr != NULL);
12820 assert(sourcecons != NULL);
12821 assert(targetcons != NULL);
12822
12823 sourcedata = SCIPconsGetData(sourcecons);
12824 assert(sourcedata != NULL);
12825 assert(sourcedata->demandrows == NULL);
12826
12827 SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12828
12829 /* get event handler */
12830 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12831 assert(conshdlrdata != NULL);
12832 assert(conshdlrdata->eventhdlr != NULL);
12833
12834 /* create constraint data for target constraint */
12835 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12836 sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12837 sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12838
12839 /* create target constraint */
12840 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12841 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12842 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12843 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12844 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12845
12846 /* catch bound change events of variables */
12847 SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12848
12849 return SCIP_OKAY;
12850}
12851
12852/** LP initialization method of constraint handler */
12853static
12854SCIP_DECL_CONSINITLP(consInitlpCumulative)
12855{
12856 SCIP_CONSHDLRDATA* conshdlrdata;
12857 int c;
12858
12859 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12860 assert(conshdlr != NULL);
12861 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12862 assert(conshdlrdata != NULL);
12863
12864 *infeasible = FALSE;
12865
12866 SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12867
12868 if( conshdlrdata->usebinvars )
12869 {
12870 /* add rows to LP */
12871 for( c = 0; c < nconss && !(*infeasible); ++c )
12872 {
12873 assert(SCIPconsIsInitial(conss[c]));
12874 SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12875
12876 if( conshdlrdata->cutsasconss )
12877 {
12879 }
12880 }
12881 }
12882
12883 /**@todo if we want to use only the integer variables; only these will be in cuts
12884 * create some initial cuts, currently these are only separated */
12885
12886 return SCIP_OKAY;
12887}
12888
12889/** separation method of constraint handler for LP solutions */
12890static
12891SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12892{
12893 SCIP_CONSHDLRDATA* conshdlrdata;
12894 SCIP_Bool cutoff;
12895 SCIP_Bool separated;
12896 int c;
12897
12898 SCIPdebugMsg(scip, "consSepalpCumulative\n");
12899
12900 assert(conshdlr != NULL);
12901 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12902 assert(nconss == 0 || conss != NULL);
12903 assert(result != NULL);
12904 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12905 assert(conshdlrdata != NULL);
12906
12907 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12908
12909 cutoff = FALSE;
12910 separated = FALSE;
12911 (*result) = SCIP_DIDNOTRUN;
12912
12913 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12914 return SCIP_OKAY;
12915
12916 (*result) = SCIP_DIDNOTFIND;
12917
12918 if( conshdlrdata->usebinvars )
12919 {
12920 /* check all useful cumulative constraints for feasibility */
12921 for( c = 0; c < nusefulconss && !cutoff; ++c )
12922 {
12923 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12924 }
12925
12926 if( !cutoff && conshdlrdata->usecovercuts )
12927 {
12928 for( c = 0; c < nusefulconss; ++c )
12929 {
12930 SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12931 }
12932 }
12933 }
12934
12935 if( conshdlrdata->sepaold )
12936 {
12937 /* separate cuts containing only integer variables */
12938 for( c = 0; c < nusefulconss; ++c )
12939 {
12940 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12941 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12942 }
12943 }
12944
12945 if( cutoff )
12946 *result = SCIP_CUTOFF;
12947 else if( separated )
12948 *result = SCIP_SEPARATED;
12949
12950 return SCIP_OKAY;
12951}
12952
12953/** separation method of constraint handler for arbitrary primal solutions */
12954static
12955SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12956{ /*lint --e{715}*/
12957 SCIP_CONSHDLRDATA* conshdlrdata;
12958 SCIP_Bool cutoff;
12959 SCIP_Bool separated;
12960 int c;
12961
12962 assert(conshdlr != NULL);
12963 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12964 assert(nconss == 0 || conss != NULL);
12965 assert(result != NULL);
12966
12967 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12968 assert(conshdlrdata != NULL);
12969
12970 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12971 return SCIP_OKAY;
12972
12973 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12974
12975 cutoff = FALSE;
12976 separated = FALSE;
12977 (*result) = SCIP_DIDNOTFIND;
12978
12979 if( conshdlrdata->usebinvars )
12980 {
12981 /* check all useful cumulative constraints for feasibility */
12982 for( c = 0; c < nusefulconss && !cutoff; ++c )
12983 {
12984 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12985 }
12986
12987 if( !cutoff && conshdlrdata->usecovercuts )
12988 {
12989 for( c = 0; c < nusefulconss; ++c )
12990 {
12991 SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12992 }
12993 }
12994 }
12995 if( conshdlrdata->sepaold )
12996 {
12997 /* separate cuts containing only integer variables */
12998 for( c = 0; c < nusefulconss; ++c )
12999 {
13000 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
13001 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
13002 }
13003 }
13004
13005 if( cutoff )
13006 *result = SCIP_CUTOFF;
13007 else if( separated )
13008 *result = SCIP_SEPARATED;
13009
13010 return SCIP_OKAY;
13011}
13012
13013/** constraint enforcing method of constraint handler for LP solutions */
13014static
13015SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
13016{ /*lint --e{715}*/
13017 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
13018
13019 return SCIP_OKAY;
13020}
13021
13022/** constraint enforcing method of constraint handler for relaxation solutions */
13023static
13024SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
13025{ /*lint --e{715}*/
13026 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
13027
13028 return SCIP_OKAY;
13029}
13030
13031/** constraint enforcing method of constraint handler for pseudo solutions */
13032static
13033SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
13034{ /*lint --e{715}*/
13035 SCIP_CONSHDLRDATA* conshdlrdata;
13036
13037 SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
13038
13039 assert(conshdlr != NULL);
13040 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13041 assert(nconss == 0 || conss != NULL);
13042 assert(result != NULL);
13043
13044 if( objinfeasible )
13045 {
13046 *result = SCIP_DIDNOTRUN;
13047 return SCIP_OKAY;
13048 }
13049
13050 (*result) = SCIP_FEASIBLE;
13051
13052 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13053 assert(conshdlrdata != NULL);
13054
13055 SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13056
13057 return SCIP_OKAY;
13058}
13059
13060/** feasibility check method of constraint handler for integral solutions */
13061static
13062SCIP_DECL_CONSCHECK(consCheckCumulative)
13063{ /*lint --e{715}*/
13064 int c;
13065
13066 assert(conshdlr != NULL);
13067 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13068 assert(nconss == 0 || conss != NULL);
13069 assert(result != NULL);
13070
13071 *result = SCIP_FEASIBLE;
13072
13073 SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13074
13075 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13076 {
13077 SCIP_Bool violated = FALSE;
13078
13079 SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13080
13081 if( violated )
13082 *result = SCIP_INFEASIBLE;
13083 }
13084
13085 return SCIP_OKAY;
13086}
13087
13088/** domain propagation method of constraint handler */
13089static
13090SCIP_DECL_CONSPROP(consPropCumulative)
13091{ /*lint --e{715}*/
13092 SCIP_CONSHDLRDATA* conshdlrdata;
13093 SCIP_Bool cutoff;
13094 int nchgbds;
13095 int ndelconss;
13096 int c;
13097#if 0
13098 int naggrvars = 0;
13099#endif
13100
13101 SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13102
13103 assert(conshdlr != NULL);
13104 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13105 assert(nconss == 0 || conss != NULL);
13106 assert(result != NULL);
13107
13108 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13109 assert(conshdlrdata != NULL);
13110
13111 nchgbds = 0;
13112 ndelconss = 0;
13113 cutoff = FALSE;
13114 (*result) = SCIP_DIDNOTRUN;
13115
13116 /* propgate all useful constraints */
13117 for( c = 0; c < nusefulconss && !cutoff; ++c )
13118 {
13119 SCIP_CONS* cons;
13120
13121 cons = conss[c];
13122 assert(cons != NULL);
13123
13124 if( SCIPgetDepth(scip) == 0 )
13125 {
13126#if 0
13128 &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13129#else
13131 &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13132#endif
13133 if( cutoff )
13134 break;
13135
13136 if( SCIPconsIsDeleted(cons) )
13137 continue;
13138 }
13139
13140 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13141 }
13142
13143 if( !cutoff && nchgbds == 0 )
13144 {
13145 /* propgate all other constraints */
13146 for( c = nusefulconss; c < nconss && !cutoff; ++c )
13147 {
13148 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13149 }
13150 }
13151
13152#if 0
13153 if( !cutoff && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 )
13154 {
13155 SCIP_CALL( propagateAllConss(scip, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13156 }
13157#endif
13158
13159 if( cutoff )
13160 {
13161 SCIPdebugMsg(scip, "detected infeasible\n");
13162 *result = SCIP_CUTOFF;
13163 }
13164 else if( nchgbds > 0 )
13165 {
13166 SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13167 *result = SCIP_REDUCEDDOM;
13168 }
13169 else
13170 *result = SCIP_DIDNOTFIND;
13171
13172 return SCIP_OKAY;
13173}
13174
13175/** presolving method of constraint handler */
13176static
13177SCIP_DECL_CONSPRESOL(consPresolCumulative)
13178{ /*lint --e{715}*/
13179 SCIP_CONSHDLRDATA* conshdlrdata;
13180 SCIP_CONS* cons;
13181 SCIP_Bool cutoff;
13182 SCIP_Bool unbounded;
13183 int oldnfixedvars;
13184 int oldnchgbds;
13185 int oldndelconss;
13186 int oldnaddconss;
13187 int oldnupgdconss;
13188 int oldnchgsides;
13189 int oldnchgcoefs;
13190 int c;
13191
13192 assert(conshdlr != NULL);
13193 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13194 assert(scip != NULL);
13195 assert(result != NULL);
13196
13197 SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13198
13199 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13200 assert(conshdlrdata != NULL);
13201
13202 *result = SCIP_DIDNOTRUN;
13203
13204 oldnfixedvars = *nfixedvars;
13205 oldnchgbds = *nchgbds;
13206 oldnchgsides = *nchgsides;
13207 oldnchgcoefs = *nchgcoefs;
13208 oldnupgdconss = *nupgdconss;
13209 oldndelconss = *ndelconss;
13210 oldnaddconss = *naddconss;
13211 cutoff = FALSE;
13212 unbounded = FALSE;
13213
13214 /* process constraints */
13215 for( c = 0; c < nconss && !cutoff; ++c )
13216 {
13217 cons = conss[c];
13218
13219 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13220 * hmax)
13221 */
13222 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13223
13224 if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13225 {
13226#if 0
13227 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13228 nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13229#else
13230 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13231 nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13232#endif
13233
13234 if( cutoff || unbounded )
13235 break;
13236
13237 if( SCIPconsIsDeleted(cons) )
13238 continue;
13239 }
13240
13241 /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13242 if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13243 {
13244 SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13245 }
13246
13247 /* strengthen existing variable bounds using the cumulative condition */
13248 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13249 {
13250 SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13251 }
13252
13253 /* propagate cumulative constraint */
13254 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13255 assert(checkDemands(scip, cons) || cutoff);
13256 }
13257
13258 if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13259 {
13260 SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13261 }
13262
13263 /* only perform the detection of variable bounds and disjunctive constraint once */
13264 if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13265 && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13266 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13267 {
13268 /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13269 * propagation
13270 */
13271 SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13272 conshdlrdata->detectedredundant = TRUE;
13273 }
13274
13275 if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13276 {
13277 SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13278 }
13279
13280 SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13281 *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13282
13283 if( cutoff )
13284 *result = SCIP_CUTOFF;
13285 else if( unbounded )
13286 *result = SCIP_UNBOUNDED;
13287 else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13288 || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13289 *result = SCIP_SUCCESS;
13290 else
13291 *result = SCIP_DIDNOTFIND;
13292
13293 return SCIP_OKAY;
13294}
13295
13296/** propagation conflict resolving method of constraint handler */
13297static
13298SCIP_DECL_CONSRESPROP(consRespropCumulative)
13299{ /*lint --e{715}*/
13300 SCIP_CONSHDLRDATA* conshdlrdata;
13301 SCIP_CONSDATA* consdata;
13302
13303 assert(conshdlr != NULL);
13304 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13305 assert(scip != NULL);
13306 assert(result != NULL);
13307 assert(infervar != NULL);
13308 assert(bdchgidx != NULL);
13309
13310 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13311 assert(conshdlrdata != NULL);
13312
13313 /* process constraint */
13314 assert(cons != NULL);
13315
13316 consdata = SCIPconsGetData(cons);
13317 assert(consdata != NULL);
13318
13319 SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13320 SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13322
13323 SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13324 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13325 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13326
13327 return SCIP_OKAY;
13328}
13329
13330/** variable rounding lock method of constraint handler */
13331static
13332SCIP_DECL_CONSLOCK(consLockCumulative)
13333{ /*lint --e{715}*/
13334 SCIP_CONSDATA* consdata;
13335 SCIP_VAR** vars;
13336 int v;
13337
13338 SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13339
13340 assert(scip != NULL);
13341 assert(cons != NULL);
13342 assert(locktype == SCIP_LOCKTYPE_MODEL);
13343
13344 consdata = SCIPconsGetData(cons);
13345 assert(consdata != NULL);
13346
13347 vars = consdata->vars;
13348 assert(vars != NULL);
13349
13350 for( v = 0; v < consdata->nvars; ++v )
13351 {
13352 if( consdata->downlocks[v] && consdata->uplocks[v] )
13353 {
13354 /* the integer start variable should not get rounded in both direction */
13355 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13356 }
13357 else if( consdata->downlocks[v] )
13358 {
13359 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13360 }
13361 else if( consdata->uplocks[v] )
13362 {
13363 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13364 }
13365 }
13366
13367 return SCIP_OKAY;
13368}
13369
13370
13371/** constraint display method of constraint handler */
13372static
13373SCIP_DECL_CONSPRINT(consPrintCumulative)
13374{ /*lint --e{715}*/
13375 assert(scip != NULL);
13376 assert(conshdlr != NULL);
13377 assert(cons != NULL);
13378
13379 consdataPrint(scip, SCIPconsGetData(cons), file);
13380
13381 return SCIP_OKAY;
13382}
13383
13384/** constraint copying method of constraint handler */
13385static
13386SCIP_DECL_CONSCOPY(consCopyCumulative)
13387{ /*lint --e{715}*/
13388 SCIP_CONSDATA* sourceconsdata;
13389 SCIP_VAR** sourcevars;
13390 SCIP_VAR** vars;
13391 const char* consname;
13392
13393 int nvars;
13394 int v;
13395
13396 sourceconsdata = SCIPconsGetData(sourcecons);
13397 assert(sourceconsdata != NULL);
13398
13399 /* get variables of the source constraint */
13400 nvars = sourceconsdata->nvars;
13401 sourcevars = sourceconsdata->vars;
13402
13403 (*valid) = TRUE;
13404
13405 if( nvars == 0 )
13406 return SCIP_OKAY;
13407
13408 /* allocate buffer array */
13409 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13410
13411 for( v = 0; v < nvars && *valid; ++v )
13412 {
13413 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13414 assert(!(*valid) || vars[v] != NULL);
13415 }
13416
13417 /* only create the target constraint, if all variables could be copied */
13418 if( *valid )
13419 {
13420 if( name != NULL )
13421 consname = name;
13422 else
13423 consname = SCIPconsGetName(sourcecons);
13424
13425 /* create a copy of the cumulative constraint */
13426 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13427 sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13428 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13429
13430 /* adjust left side if the time axis if needed */
13431 if( sourceconsdata->hmin > 0 )
13432 {
13433 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13434 }
13435
13436 /* adjust right side if the time axis if needed */
13437 if( sourceconsdata->hmax < INT_MAX )
13438 {
13439 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13440 }
13441 }
13442
13443 /* free buffer array */
13444 SCIPfreeBufferArray(scip, &vars);
13445
13446 return SCIP_OKAY;
13447}
13448
13449
13450/** constraint parsing method of constraint handler */
13451static
13452SCIP_DECL_CONSPARSE(consParseCumulative)
13453{ /*lint --e{715}*/
13454 SCIP_VAR** vars;
13455 SCIP_VAR* var;
13456 SCIP_Real value;
13457 char strvalue[SCIP_MAXSTRLEN];
13458 char* endptr;
13459 int* demands;
13460 int* durations;
13461 int capacity;
13462 int duration;
13463 int demand;
13464 int hmin;
13465 int hmax;
13466 int varssize;
13467 int nvars;
13468
13469 SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13470
13471 *success = TRUE;
13472
13473 /* cutoff "cumulative" form the constraint string */
13474 SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13475 str = endptr;
13476
13477 varssize = 100;
13478 nvars = 0;
13479
13480 /* allocate buffer array for variables */
13481 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13482 SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13483 SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13484
13485 do
13486 {
13487 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13488
13489 if( var == NULL )
13490 {
13491 endptr = strchr(endptr, ')');
13492
13493 if( endptr == NULL )
13494 *success = FALSE;
13495 else
13496 str = endptr;
13497
13498 break;
13499 }
13500
13501 str = endptr;
13502 SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13503 duration = atoi(strvalue);
13504 str = endptr;
13505
13506 SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13507 demand = atoi(strvalue);
13508 str = endptr;
13509
13510 SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13511
13512 vars[nvars] = var;
13513 demands[nvars] = demand;
13514 durations[nvars] = duration;
13515 nvars++;
13516 }
13517 while( *str != ')' );
13518
13519 if( *success )
13520 {
13521 /* parse effective time window */
13522 SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13523 hmin = atoi(strvalue);
13524 str = endptr;
13525
13526 if( SCIPparseReal(scip, str, &value, &endptr) )
13527 {
13528 hmax = (int)(value);
13529 str = endptr;
13530
13531 /* parse capacity */
13532 SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13533 str = endptr;
13534 if( SCIPparseReal(scip, str, &value, &endptr) )
13535 {
13536 capacity = (int)value;
13537
13538 /* create cumulative constraint */
13539 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13540 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13541
13542 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13543 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13544 }
13545 }
13546 }
13547
13548 /* free buffer arrays */
13549 SCIPfreeBufferArray(scip, &durations);
13550 SCIPfreeBufferArray(scip, &demands);
13551 SCIPfreeBufferArray(scip, &vars);
13552
13553 return SCIP_OKAY;
13554}
13555
13556
13557/** constraint method of constraint handler which returns the variables (if possible) */
13558static
13559SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13560{ /*lint --e{715}*/
13561 SCIP_CONSDATA* consdata;
13562
13563 consdata = SCIPconsGetData(cons);
13564 assert(consdata != NULL);
13565
13566 if( varssize < consdata->nvars )
13567 (*success) = FALSE;
13568 else
13569 {
13570 assert(vars != NULL);
13571
13572 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13573 (*success) = TRUE;
13574 }
13575
13576 return SCIP_OKAY;
13577}
13578
13579/** constraint method of constraint handler which returns the number of variables (if possible) */
13580static
13581SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13582{ /*lint --e{715}*/
13583 SCIP_CONSDATA* consdata;
13584
13585 consdata = SCIPconsGetData(cons);
13586 assert(consdata != NULL);
13587
13588 (*nvars) = consdata->nvars;
13589 (*success) = TRUE;
13590
13591 return SCIP_OKAY;
13592}
13593
13594/**@} */
13595
13596/**@name Callback methods of event handler
13597 *
13598 * @{
13599 */
13600
13601
13602/** execution method of event handler */
13603static
13604SCIP_DECL_EVENTEXEC(eventExecCumulative)
13605{ /*lint --e{715}*/
13606 SCIP_CONSDATA* consdata;
13607
13608 assert(scip != NULL);
13609 assert(eventhdlr != NULL);
13610 assert(eventdata != NULL);
13611 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13612 assert(event != NULL);
13613
13614 consdata = (SCIP_CONSDATA*)eventdata;
13615 assert(consdata != NULL);
13616
13617 /* mark the constraint to be not propagated */
13618 consdata->propagated = FALSE;
13619
13620 return SCIP_OKAY;
13621}
13622
13623/**@} */
13624
13625/*
13626 * constraint specific interface methods
13627 */
13628
13629/** creates the handler for cumulative constraints and includes it in SCIP */
13631 SCIP* scip /**< SCIP data structure */
13632 )
13633{
13634 SCIP_CONSHDLRDATA* conshdlrdata;
13635 SCIP_CONSHDLR* conshdlr;
13636 SCIP_EVENTHDLR* eventhdlr;
13637
13638 /* create event handler for bound change events */
13639 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13640
13641 /* create cumulative constraint handler data */
13642 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13643
13644 /* include constraint handler */
13647 consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13648 conshdlrdata) );
13649
13650 assert(conshdlr != NULL);
13651
13652 /* set non-fundamental callbacks via specific setter functions */
13653 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13654 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13655#ifdef SCIP_STATISTIC
13656 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13657#endif
13658 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13659 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13660 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13661 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13662 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13663 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13664 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13665 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13667 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13670 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13671 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13673 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13674 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13675
13676 /* add cumulative constraint handler parameters */
13678 "constraints/" CONSHDLR_NAME "/ttinfer",
13679 "should time-table (core-times) propagator be used to infer bounds?",
13680 &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13682 "constraints/" CONSHDLR_NAME "/efcheck",
13683 "should edge-finding be used to detect an overload?",
13684 &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13686 "constraints/" CONSHDLR_NAME "/efinfer",
13687 "should edge-finding be used to infer bounds?",
13688 &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13690 "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13691 &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13693 "constraints/" CONSHDLR_NAME "/ttefcheck",
13694 "should time-table edge-finding be used to detect an overload?",
13695 &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13697 "constraints/" CONSHDLR_NAME "/ttefinfer",
13698 "should time-table edge-finding be used to infer bounds?",
13699 &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13700
13702 "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13703 &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13705 "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13706 &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13708 "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13709 &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13711 "constraints/" CONSHDLR_NAME "/cutsasconss",
13712 "should the cumulative constraint create cuts as knapsack constraints?",
13713 &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13715 "constraints/" CONSHDLR_NAME "/sepaold",
13716 "shall old sepa algo be applied?",
13717 &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13718
13720 "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13721 &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13722
13723 /* presolving parameters */
13725 "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13726 &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13728 "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13729 &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13731 "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13732 &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13734 "constraints/" CONSHDLR_NAME "/presolpairwise",
13735 "should pairwise constraint comparison be performed in presolving?",
13736 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13738 "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13739 &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13740
13742 "constraints/" CONSHDLR_NAME "/maxnodes",
13743 "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13744 &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13746 "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13747 &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13749 "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13750 &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13751
13752 /* conflict analysis parameters */
13754 "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13755 &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13756
13757 return SCIP_OKAY;
13758}
13759
13760/** creates and captures a cumulative constraint */
13762 SCIP* scip, /**< SCIP data structure */
13763 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13764 const char* name, /**< name of constraint */
13765 int nvars, /**< number of variables (jobs) */
13766 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13767 int* durations, /**< array containing corresponding durations */
13768 int* demands, /**< array containing corresponding demands */
13769 int capacity, /**< available cumulative capacity */
13770 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13771 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13772 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13773 * Usually set to TRUE. */
13774 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13775 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13776 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13777 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13778 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13779 * Usually set to TRUE. */
13780 SCIP_Bool local, /**< is constraint only valid locally?
13781 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13782 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13783 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13784 * adds coefficients to this constraint. */
13785 SCIP_Bool dynamic, /**< is constraint subject to aging?
13786 * Usually set to FALSE. Set to TRUE for own cuts which
13787 * are seperated as constraints. */
13788 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13789 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13790 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13791 * if it may be moved to a more global node?
13792 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13793 )
13794{
13795 SCIP_CONSHDLR* conshdlr;
13796 SCIP_CONSDATA* consdata;
13797
13798 assert(scip != NULL);
13799
13800 /* find the cumulative constraint handler */
13801 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13802 if( conshdlr == NULL )
13803 {
13804 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13805 return SCIP_PLUGINNOTFOUND;
13806 }
13807
13808 SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13809
13810 /* create constraint data */
13811 SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13812
13813 /* create constraint */
13814 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13815 initial, separate, enforce, check, propagate,
13816 local, modifiable, dynamic, removable, stickingatnode) );
13817
13819 {
13820 SCIP_CONSHDLRDATA* conshdlrdata;
13821
13822 /* get event handler */
13823 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13824 assert(conshdlrdata != NULL);
13825 assert(conshdlrdata->eventhdlr != NULL);
13826
13827 /* catch bound change events of variables */
13828 SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13829 }
13830
13831 return SCIP_OKAY;
13832}
13833
13834/** creates and captures a cumulative constraint
13835 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13836 * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13837 *
13838 * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13839 *
13840 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13841 */
13843 SCIP* scip, /**< SCIP data structure */
13844 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13845 const char* name, /**< name of constraint */
13846 int nvars, /**< number of variables (jobs) */
13847 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13848 int* durations, /**< array containing corresponding durations */
13849 int* demands, /**< array containing corresponding demands */
13850 int capacity /**< available cumulative capacity */
13851 )
13852{
13853 assert(scip != NULL);
13854
13855 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13857
13858 return SCIP_OKAY;
13859}
13860
13861/** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13863 SCIP* scip, /**< SCIP data structure */
13864 SCIP_CONS* cons, /**< constraint data */
13865 int hmin /**< left bound of time axis to be considered */
13866 )
13867{
13868 SCIP_CONSDATA* consdata;
13869 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13870 {
13871 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13872 return SCIP_INVALIDCALL;
13873 }
13874
13875 consdata = SCIPconsGetData(cons);
13876 assert(consdata != NULL);
13877 assert(hmin >= 0);
13878 assert(hmin <= consdata->hmax);
13879
13880 consdata->hmin = hmin;
13881
13882 return SCIP_OKAY;
13883}
13884
13885/** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13887 SCIP* scip, /**< SCIP data structure */
13888 SCIP_CONS* cons /**< constraint */
13889 )
13890{
13891 SCIP_CONSDATA* consdata;
13892 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13893 {
13894 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13895 SCIPABORT();
13896 return 0; /*lint !e527*/
13897 }
13898
13899 consdata = SCIPconsGetData(cons);
13900 assert(consdata != NULL);
13901
13902 return consdata->hmin;
13903}
13904
13905/** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13907 SCIP* scip, /**< SCIP data structure */
13908 SCIP_CONS* cons, /**< constraint data */
13909 int hmax /**< right bound of time axis to be considered */
13910 )
13911{
13912 SCIP_CONSDATA* consdata;
13913 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13914 {
13915 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13916 SCIPABORT();
13917 return SCIP_INVALIDCALL; /*lint !e527*/
13918 }
13919
13920 consdata = SCIPconsGetData(cons);
13921 assert(consdata != NULL);
13922 assert(hmax >= consdata->hmin);
13923
13924 consdata->hmax = hmax;
13925
13926 return SCIP_OKAY;
13927}
13928
13929/** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13931 SCIP* scip, /**< SCIP data structure */
13932 SCIP_CONS* cons /**< constraint */
13933 )
13934{
13935 SCIP_CONSDATA* consdata;
13936 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13937 {
13938 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13939 SCIPABORT();
13940 return 0; /*lint !e527*/
13941 }
13942
13943 consdata = SCIPconsGetData(cons);
13944 assert(consdata != NULL);
13945
13946 return consdata->hmax;
13947}
13948
13949/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13951 SCIP* scip, /**< SCIP data structure */
13952 SCIP_CONS* cons /**< constraint data */
13953 )
13954{
13955 SCIP_CONSDATA* consdata;
13956
13957 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13958 {
13959 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13960 SCIPABORT();
13961 return NULL; /*lint !e527*/
13962 }
13963
13964 consdata = SCIPconsGetData(cons);
13965 assert(consdata != NULL);
13966
13967 return consdata->vars;
13968}
13969
13970/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13972 SCIP* scip, /**< SCIP data structure */
13973 SCIP_CONS* cons /**< constraint data */
13974 )
13975{
13976 SCIP_CONSDATA* consdata;
13977
13978 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13979 {
13980 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13981 SCIPABORT();
13982 return -1; /*lint !e527*/
13983 }
13984
13985 consdata = SCIPconsGetData(cons);
13986 assert(consdata != NULL);
13987
13988 return consdata->nvars;
13989}
13990
13991/** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13993 SCIP* scip, /**< SCIP data structure */
13994 SCIP_CONS* cons /**< constraint data */
13995 )
13996{
13997 SCIP_CONSDATA* consdata;
13998
13999 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14000 {
14001 SCIPerrorMessage("constraint is not a cumulative constraint\n");
14002 SCIPABORT();
14003 return -1; /*lint !e527*/
14004 }
14005
14006 consdata = SCIPconsGetData(cons);
14007 assert(consdata != NULL);
14008
14009 return consdata->capacity;
14010}
14011
14012/** returns the durations of the cumulative constraint */ /*lint -e{715}*/
14014 SCIP* scip, /**< SCIP data structure */
14015 SCIP_CONS* cons /**< constraint data */
14016 )
14017{
14018 SCIP_CONSDATA* consdata;
14019
14020 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14021 {
14022 SCIPerrorMessage("constraint is not a cumulative constraint\n");
14023 SCIPABORT();
14024 return NULL; /*lint !e527*/
14025 }
14026
14027 consdata = SCIPconsGetData(cons);
14028 assert(consdata != NULL);
14029
14030 return consdata->durations;
14031}
14032
14033/** returns the demands of the cumulative constraint */ /*lint -e{715}*/
14035 SCIP* scip, /**< SCIP data structure */
14036 SCIP_CONS* cons /**< constraint data */
14037 )
14038{
14039 SCIP_CONSDATA* consdata;
14040
14041 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14042 {
14043 SCIPerrorMessage("constraint is not a cumulative constraint\n");
14044 SCIPABORT();
14045 return NULL; /*lint !e527*/
14046 }
14047
14048 consdata = SCIPconsGetData(cons);
14049 assert(consdata != NULL);
14050
14051 return consdata->demands;
14052}
14053
14054/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14055 * given solution is satisfied
14056 */
14058 SCIP* scip, /**< SCIP data structure */
14059 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14060 int nvars, /**< number of variables (jobs) */
14061 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14062 int* durations, /**< array containing corresponding durations */
14063 int* demands, /**< array containing corresponding demands */
14064 int capacity, /**< available cumulative capacity */
14065 int hmin, /**< left bound of time axis to be considered (including hmin) */
14066 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14067 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14068 SCIP_CONS* cons, /**< constraint which is checked */
14069 SCIP_Bool printreason /**< should the reason for the violation be printed? */
14070 )
14071{
14072 assert(scip != NULL);
14073 assert(violated != NULL);
14074
14075 SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14076 violated, cons, printreason) );
14077
14078 return SCIP_OKAY;
14079}
14080
14081/** normalize cumulative condition */ /*lint -e{715}*/
14083 SCIP* scip, /**< SCIP data structure */
14084 int nvars, /**< number of start time variables (activities) */
14085 SCIP_VAR** vars, /**< array of start time variables */
14086 int* durations, /**< array of durations */
14087 int* demands, /**< array of demands */
14088 int* capacity, /**< pointer to store the changed cumulative capacity */
14089 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14090 int* nchgsides /**< pointer to count number of side changes */
14091 )
14092{ /*lint --e{715}*/
14093 normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
14094
14095 return SCIP_OKAY;
14096}
14097
14098/** searches for a time point within the cumulative condition were the cumulative condition can be split */
14100 SCIP* scip, /**< SCIP data structure */
14101 int nvars, /**< number of variables (jobs) */
14102 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14103 int* durations, /**< array containing corresponding durations */
14104 int* demands, /**< array containing corresponding demands */
14105 int capacity, /**< available cumulative capacity */
14106 int* hmin, /**< pointer to store the left bound of the effective horizon */
14107 int* hmax, /**< pointer to store the right bound of the effective horizon */
14108 int* split /**< point were the cumulative condition can be split */
14109 )
14110{
14111 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14112 hmin, hmax, split) );
14113
14114 return SCIP_OKAY;
14115}
14116
14117/** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14119 SCIP* scip, /**< SCIP data structure */
14120 int nvars, /**< number of start time variables (activities) */
14121 SCIP_VAR** vars, /**< array of start time variables */
14122 int* durations, /**< array of durations */
14123 int hmin, /**< left bound of time axis to be considered */
14124 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14125 SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14126 SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14127 SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14128 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14129 int* nfixedvars, /**< pointer to store the number of fixed variables */
14130 int* nchgsides, /**< pointer to store the number of changed sides */
14131 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14132 )
14133{
14134 if( nvars <= 1 )
14135 return SCIP_OKAY;
14136
14137 /* presolve constraint form the earlier start time point of view */
14138 SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14139 irrelevants, nfixedvars, nchgsides, cutoff) );
14140
14141 /* presolve constraint form the latest completion time point of view */
14142 SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14143 irrelevants, nfixedvars, nchgsides, cutoff) );
14144
14145 return SCIP_OKAY;
14146}
14147
14148/** propagate the given cumulative condition */
14150 SCIP* scip, /**< SCIP data structure */
14151 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14152 int nvars, /**< number of variables (jobs) */
14153 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14154 int* durations, /**< array containing corresponding durations */
14155 int* demands, /**< array containing corresponding demands */
14156 int capacity, /**< available cumulative capacity */
14157 int hmin, /**< left bound of time axis to be considered (including hmin) */
14158 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14159 SCIP_CONS* cons, /**< constraint which gets propagated */
14160 int* nchgbds, /**< pointer to store the number of variable bound changes */
14161 SCIP_Bool* initialized, /**< was conflict analysis initialized */
14162 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14163 SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14164 )
14165{
14166 SCIP_CONSHDLR* conshdlr;
14167 SCIP_CONSHDLRDATA* conshdlrdata;
14168 SCIP_Bool redundant;
14169
14170 assert(scip != NULL);
14171 assert(cons != NULL);
14172 assert(initialized != NULL);
14173 assert(*initialized == FALSE);
14174 assert(cutoff != NULL);
14175 assert(*cutoff == FALSE);
14176
14177 /* find the cumulative constraint handler */
14178 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14179 if( conshdlr == NULL )
14180 {
14181 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14182 return SCIP_PLUGINNOTFOUND;
14183 }
14184
14185 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14186 assert(conshdlrdata != NULL);
14187
14188 redundant = FALSE;
14189
14190 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14191 nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14192 nchgbds, &redundant, initialized, explanation, cutoff) );
14193
14194 return SCIP_OKAY;
14195}
14196
14197/** resolve propagation w.r.t. the cumulative condition */
14199 SCIP* scip, /**< SCIP data structure */
14200 int nvars, /**< number of start time variables (activities) */
14201 SCIP_VAR** vars, /**< array of start time variables */
14202 int* durations, /**< array of durations */
14203 int* demands, /**< array of demands */
14204 int capacity, /**< cumulative capacity */
14205 int hmin, /**< left bound of time axis to be considered (including hmin) */
14206 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14207 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14208 int inferinfo, /**< the user information */
14209 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14210 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14211 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14212 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14213 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14214 )
14215{
14216 SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14217 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14218
14219 return SCIP_OKAY;
14220}
14221
14222/** this method visualizes the cumulative structure in GML format */
14224 SCIP* scip, /**< SCIP data structure */
14225 SCIP_CONS* cons /**< cumulative constraint */
14226 )
14227{
14228 SCIP_CONSDATA* consdata;
14229 SCIP_HASHTABLE* vars;
14230 FILE* file;
14231 SCIP_VAR* var;
14232 char filename[SCIP_MAXSTRLEN];
14233 int nvars;
14234 int v;
14235
14236 SCIP_RETCODE retcode = SCIP_OKAY;
14237
14238 /* open file */
14239 (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14240 file = fopen(filename, "w");
14241
14242 /* check if the file was open */
14243 if( file == NULL )
14244 {
14245 SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14246 SCIPprintSysError(filename);
14247 return SCIP_FILECREATEERROR;
14248 }
14249
14250 consdata = SCIPconsGetData(cons);
14251 assert(consdata != NULL);
14252
14253 nvars = consdata->nvars;
14254
14255 SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14256 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14257
14258 /* create opening of the GML format */
14260
14261 for( v = 0; v < nvars; ++v )
14262 {
14263 char color[SCIP_MAXSTRLEN];
14264
14265 var = consdata->vars[v];
14266 assert(var != NULL);
14267
14268 SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14269
14270 if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14271 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14272 else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14273 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14274 else
14275 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14276
14277 SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14278 }
14279
14280 for( v = 0; v < nvars; ++v )
14281 {
14282 SCIP_VAR** vbdvars;
14283 int nvbdvars;
14284 int b;
14285
14286 var = consdata->vars[v];
14287 assert(var != NULL);
14288
14289 vbdvars = SCIPvarGetVlbVars(var);
14290 nvbdvars = SCIPvarGetNVlbs(var);
14291
14292 for( b = 0; b < nvbdvars; ++b )
14293 {
14294 if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14295 {
14296 SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14297 }
14298 }
14299
14300#if 0
14301 vbdvars = SCIPvarGetVubVars(var);
14302 nvbdvars = SCIPvarGetNVubs(var);
14303
14304 for( b = 0; b < nvbdvars; ++b )
14305 {
14306 if( SCIPhashtableExists(vars, vbdvars[b]) )
14307 {
14308 SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14309 }
14310 }
14311#endif
14312 }
14313
14314 /* create closing of the GML format */
14315 SCIPgmlWriteClosing(file);
14316TERMINATE:
14317 /* close file */
14318 fclose(file);
14319
14320 SCIPhashtableFree(&vars);
14321
14322 return retcode;
14323}
14324
14325/** sets method to solve an individual cumulative condition */
14327 SCIP* scip, /**< SCIP data structure */
14328 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14329 )
14330{
14331 SCIP_CONSHDLR* conshdlr;
14332 SCIP_CONSHDLRDATA* conshdlrdata;
14333
14334 /* find the cumulative constraint handler */
14335 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14336 if( conshdlr == NULL )
14337 {
14338 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14339 return SCIP_PLUGINNOTFOUND;
14340 }
14341
14342 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14343 assert(conshdlrdata != NULL);
14344
14345 conshdlrdata->solveCumulative = solveCumulative;
14346
14347 return SCIP_OKAY;
14348}
14349
14350/** solves given cumulative condition as independent sub problem
14351 *
14352 * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14353 * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14354 * solver was interrupted.
14355 */
14357 SCIP* scip, /**< SCIP data structure */
14358 int njobs, /**< number of jobs (activities) */
14359 SCIP_Real* ests, /**< array with the earlier start time for each job */
14360 SCIP_Real* lsts, /**< array with the latest start time for each job */
14361 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14362 int* durations, /**< array of durations */
14363 int* demands, /**< array of demands */
14364 int capacity, /**< cumulative capacity */
14365 int hmin, /**< left bound of time axis to be considered (including hmin) */
14366 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14367 SCIP_Real timelimit, /**< time limit for solving in seconds */
14368 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14369 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14370 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14371 SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14372 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14373 SCIP_Bool* error /**< pointer to store if an error occurred */
14374 )
14375{
14376 SCIP_CONSHDLR* conshdlr;
14377 SCIP_CONSHDLRDATA* conshdlrdata;
14378
14379 (*solved) = TRUE;
14380 (*infeasible) = FALSE;
14381 (*unbounded) = FALSE;
14382 (*error) = FALSE;
14383
14384 if( njobs == 0 )
14385 return SCIP_OKAY;
14386
14387 /* find the cumulative constraint handler */
14388 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14389 if( conshdlr == NULL )
14390 {
14391 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14392 (*error) = TRUE;
14393 return SCIP_PLUGINNOTFOUND;
14394 }
14395
14396 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14397 assert(conshdlrdata != NULL);
14398
14399 /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14400 if( timelimit > 0.0 && memorylimit > 10 )
14401 {
14402 SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14403 hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14404 }
14405
14406 return SCIP_OKAY;
14407}
14408
14409/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14410 * completion time
14411 */
14413 SCIP* scip, /**< SCIP data structure */
14414 SCIP_PROFILE* profile, /**< resource profile */
14415 int nvars, /**< number of variables (jobs) */
14416 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14417 int* durations, /**< array containing corresponding durations */
14418 int* demands /**< array containing corresponding demands */
14419 )
14420{
14421 SCIP_VAR* var;
14422 SCIP_HASHMAP* addedvars;
14423 int* copydemands;
14424 int* perm;
14425 int duration;
14426 int impliedest;
14427 int est;
14428 int impliedlct;
14429 int lct;
14430 int v;
14431
14432 /* create hash map for variables which are added, mapping to their duration */
14433 SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14434
14435 SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14436 SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14437
14438 /* sort variables w.r.t. job demands */
14439 for( v = 0; v < nvars; ++v )
14440 {
14441 copydemands[v] = demands[v];
14442 perm[v] = v;
14443 }
14444 SCIPsortDownIntInt(copydemands, perm, nvars);
14445
14446 /* add each job with its earliest start and latest completion time into the resource profile */
14447 for( v = 0; v < nvars; ++v )
14448 {
14449 int idx;
14450
14451 idx = perm[v];
14452 assert(idx >= 0 && idx < nvars);
14453
14454 var = vars[idx];
14455 assert(var != NULL);
14456
14457 duration = durations[idx];
14458 assert(duration > 0);
14459
14461 SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14462
14463 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14464 SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14465
14466 if( impliedest < impliedlct )
14467 {
14468 SCIP_Bool infeasible;
14469 int pos;
14470
14471 SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14472 assert(!infeasible);
14473 assert(pos == -1);
14474 }
14475
14476 if( est == impliedest && lct == impliedlct )
14477 {
14478 SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14479 }
14480 }
14481
14482 SCIPfreeBufferArray(scip, &copydemands);
14483 SCIPfreeBufferArray(scip, &perm);
14484
14485 SCIPhashmapFree(&addedvars);
14486
14487 return SCIP_OKAY;
14488}
14489
14490/** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14492 SCIP* scip, /**< SCIP data structure */
14493 SCIP_PROFILE* profile, /**< worst case resource profile */
14494 int capacity /**< capacity to check */
14495 )
14496{
14497 int* timepoints;
14498 int* loads;
14499 int ntimepoints;
14500 int t;
14501
14502 ntimepoints = SCIPprofileGetNTimepoints(profile);
14503 timepoints = SCIPprofileGetTimepoints(profile);
14504 loads = SCIPprofileGetLoads(profile);
14505
14506 /* find first time point which potentially violates the capacity restriction */
14507 for( t = 0; t < ntimepoints - 1; ++t )
14508 {
14509 /* check if the time point exceed w.r.t. worst case profile the capacity */
14510 if( loads[t] > capacity )
14511 {
14512 assert(t == 0 || loads[t-1] <= capacity);
14513 return timepoints[t];
14514 }
14515 }
14516
14517 return INT_MAX;
14518}
14519
14520/** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */ /*lint -e{715}*/
14522 SCIP* scip, /**< SCIP data structure */
14523 SCIP_PROFILE* profile, /**< worst case profile */
14524 int capacity /**< capacity to check */
14525 )
14526{
14527 int* timepoints;
14528 int* loads;
14529 int ntimepoints;
14530 int t;
14531
14532 ntimepoints = SCIPprofileGetNTimepoints(profile);
14533 timepoints = SCIPprofileGetTimepoints(profile);
14534 loads = SCIPprofileGetLoads(profile);
14535
14536 /* find last time point which potentially violates the capacity restriction */
14537 for( t = ntimepoints - 1; t >= 0; --t )
14538 {
14539 /* check if at time point t the worst case resource profile exceeds the capacity */
14540 if( loads[t] > capacity )
14541 {
14542 assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14543 return timepoints[t+1];
14544 }
14545 }
14546
14547 return INT_MIN;
14548}
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:267
#define SCIP_MAXSTRLEN
Definition: def.h:288
#define SCIP_Longint
Definition: def.h:158
#define SCIP_INVALID
Definition: def.h:193
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:243
#define SCIP_Real
Definition: def.h:173
#define SCIP_UNKNOWN
Definition: def.h:194
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:239
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:395
#define SCIP_LONGINT_FORMAT
Definition: def.h:165
#define MIN3(x, y, z)
Definition: def.h:251
#define SCIPABORT()
Definition: def.h:346
#define SCIP_LONGINT_MAX
Definition: def.h:159
#define SCIP_CALL(x)
Definition: def.h:374
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:416
#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:8947
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:8816
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:9059
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8958
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8741
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8856
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8786
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:8677
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8884
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:8919
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8866
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8933
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:8796
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8977
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8806
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:9082
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8846
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:9069
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:9391
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:9522
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:497
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:699
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:683
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:639
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:596
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:724
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:339
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:307
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:498
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1668
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip_prob.c:3184
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:3042
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:3108
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3281
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3261
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3074
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3423
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3192
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3439
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2346
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2659
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2296
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2547
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3474
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:9121
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11184
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:10370
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10396
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:2169
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:129
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3485
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2498
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:670
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:17620
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5203
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18270
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4351
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18292
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17748
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:17538
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3353
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18144
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17561
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:8401
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:5615
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17926
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5320
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:17584
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:18088
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17758
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4259
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:6661
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4437
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:17768
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17419
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18302
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18312
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:17630
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18134
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18282
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:18078
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8715
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8276
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:5501
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:11942
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:18344
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18324
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18334
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3295
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8629
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6827
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6873
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6817
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6769
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6859
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:6837
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6755
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6847
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:7050
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:7020
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6785
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:5538
void SCIPsortInt(int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:11007
void SCIPprintSysError(const char *message)
Definition: misc.c:10769
#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