SCIP Doxygen Documentation
 
Loading...
Searching...
No Matches
cons_cumulative.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-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;
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
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
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;
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
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
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
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
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
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
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];
573
574 var = consdata->vars[varidx];
575 duration = consdata->durations[varidx];
576 demand = consdata->demands[varidx];
577 assert(var != NULL);
578
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 */
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;
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);
661
662 counter = 0;
663 sumofstarts = 0;
664
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];
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);
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 )
737 else
739
740 startindices[j] = j;
741
742 if( local )
744 else
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);
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
783 startindices[j] = j;
784
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);
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 */
831 continue;
832
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",
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 {
851 continue;
852
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",
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);
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
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
934 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
936
937 /* create event point arrays */
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
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];
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 */
1036 SCIPfreeBufferArray(scip, &startindices);
1039
1040 return SCIP_OKAY;
1041}
1042
1043/** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1044static
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;
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
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;
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) );
1148
1149 ntimepoints = 0;
1151
1153 consdata->durations, consdata->demands,
1154 capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1155 &ntimepoints, &maxdemand, &minfreecapacity) );
1156
1157 /* free buffer arrays */
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 */
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
1392 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1393 return SCIP_INVALIDDATA;
1394 }
1395 }
1396
1397 /* release all variables */
1398 for( v = 0; v < njobs; ++v )
1399 {
1400 SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1401 }
1402
1403 SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1404
1405 return SCIP_OKAY;
1406}
1407
1408/** solve single cumulative condition using SCIP and a single cumulative constraint */
1409static
1411{
1412 SCIP* subscip;
1413
1414 SCIP_RETCODE retcode;
1415
1416 assert(njobs > 0);
1417
1418 (*solved) = FALSE;
1419 (*infeasible) = FALSE;
1420 (*unbounded) = FALSE;
1421 (*error) = FALSE;
1422
1423 SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1424
1425 /* initialize the sub-problem */
1426 SCIP_CALL( SCIPcreate(&subscip) );
1427
1428 /* create and solve the subproblem. catch possible errors */
1429 retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1430 njobs, capacity, hmin, hmax,
1431 maxnodes, timelimit, memorylimit,
1432 ests, lsts,
1433 infeasible, unbounded, solved, error);
1434
1435 /* free the subscip in any case */
1436 SCIP_CALL( SCIPfree(&subscip) );
1437
1438 SCIP_CALL( retcode );
1439
1440 return SCIP_OKAY;
1441}
1442
1443#if 0
1444/** solve single cumulative condition using SCIP and the time indexed formulation */
1445static
1447{
1448 SCIP* subscip;
1449 SCIP_VAR*** binvars;
1450 SCIP_RETCODE retcode;
1451 char name[SCIP_MAXSTRLEN];
1452 int minest;
1453 int maxlct;
1454 int t;
1455 int v;
1456
1457 assert(njobs > 0);
1458
1459 (*solved) = FALSE;
1460 (*infeasible) = FALSE;
1461 (*unbounded) = FALSE;
1462 (*error) = FALSE;
1463
1464 SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1465
1466 /* initialize the sub-problem */
1467 SCIP_CALL( SCIPcreate(&subscip) );
1468
1469 /* copy all plugins */
1471
1472 /* create the subproblem */
1473 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1474
1475 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1476
1477 minest = INT_MAX;
1478 maxlct = INT_MIN;
1479
1480 /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1481 * partitioning constrain which forces that job starts
1482 */
1483 for( v = 0; v < njobs; ++v )
1484 {
1485 SCIP_CONS* cons;
1486 SCIP_Real objval;
1487 int timeinterval;
1488 int est;
1489 int lst;
1490
1491 if( objvals == NULL )
1492 objval = 0.0;
1493 else
1494 objval = objvals[v];
1495
1496 est = ests[v];
1497 lst = lsts[v];
1498
1499 /* compute number of possible start points */
1500 timeinterval = lst - est + 1;
1501 assert(timeinterval > 0);
1502
1503 /* compute the smallest earliest start time and largest latest completion time */
1504 minest = MIN(minest, est);
1505 maxlct = MAX(maxlct, lst + durations[v]);
1506
1507 /* construct constraint name */
1508 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1509
1510 SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1511
1512 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1513
1514 for( t = 0; t < timeinterval; ++t )
1515 {
1516 SCIP_VAR* binvar;
1517
1518 /* construct varibale name */
1519 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1520
1521 SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1522 SCIP_CALL( SCIPaddVar(subscip, binvar) );
1523
1524 /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1525 SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1526
1527 binvars[v][t] = binvar;
1528 }
1529
1530 /* add and release the set partitioning constraint */
1531 SCIP_CALL( SCIPaddCons(subscip, cons) );
1532 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1533 }
1534
1535 /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1536 hmin = MAX(hmin, minest);
1537 hmax = MIN(hmax, maxlct);
1538 assert(hmin > INT_MIN);
1539 assert(hmax < INT_MAX);
1540 assert(hmin < hmax);
1541
1542 /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1543 for( t = hmin; t < hmax; ++t )
1544 {
1545 SCIP_CONS* cons;
1546
1547 /* construct constraint name */
1548 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1549
1550 /* create an empty knapsack constraint */
1551 SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1552
1553 /* add all jobs which potentially can be processed at that time point */
1554 for( v = 0; v < njobs; ++v )
1555 {
1556 int duration;
1557 int demand;
1558 int start;
1559 int end;
1560 int est;
1561 int lst;
1562 int k;
1563
1564 est = ests[v];
1565 lst = lsts[v] ;
1566
1567 duration = durations[v];
1568 assert(duration > 0);
1569
1570 /* check if the varibale is processed potentially at time point t */
1571 if( t < est || t >= lst + duration )
1572 continue;
1573
1574 demand = demands[v];
1575 assert(demand >= 0);
1576
1577 start = MAX(t - duration + 1, est);
1578 end = MIN(t, lst);
1579
1580 assert(start <= end);
1581
1582 for( k = start; k <= end; ++k )
1583 {
1584 assert(binvars[v][k] != NULL);
1585 SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1586 }
1587 }
1588
1589 /* add and release the knapsack constraint */
1590 SCIP_CALL( SCIPaddCons(subscip, cons) );
1591 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1592 }
1593
1594 /* do not abort subproblem on CTRL-C */
1595 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1596
1597 /* disable output to console */
1598 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1599
1600 /* set limits for the subproblem */
1601 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1602 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1603 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1604
1605 /* solve single cumulative constraint by branch and bound */
1606 retcode = SCIPsolve(subscip);
1607
1608 if( retcode != SCIP_OKAY )
1609 (*error) = TRUE;
1610 else
1611 {
1612 SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1613
1614 /* evaluated solution status */
1615 switch( SCIPgetStatus(subscip) )
1616 {
1619 (*infeasible) = TRUE;
1620 (*solved) = TRUE;
1621 break;
1623 (*unbounded) = TRUE;
1624 (*solved) = TRUE;
1625 break;
1627 {
1628 SCIP_SOL* sol;
1629
1630 sol = SCIPgetBestSol(subscip);
1631 assert(sol != NULL);
1632
1633 for( v = 0; v < njobs; ++v )
1634 {
1635 int timeinterval;
1636 int est;
1637 int lst;
1638
1639 est = ests[v];
1640 lst = lsts[v];
1641
1642 /* compute number of possible start points */
1643 timeinterval = lst - est + 1;
1644
1645 /* check which binary varibale is set to one */
1646 for( t = 0; t < timeinterval; ++t )
1647 {
1648 if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1649 {
1650 ests[v] = est + t;
1651 lsts[v] = est + t;
1652 break;
1653 }
1654 }
1655 }
1656
1657 (*solved) = TRUE;
1658 break;
1659 }
1665 /* transfer the global bound changes */
1666 for( v = 0; v < njobs; ++v )
1667 {
1668 int timeinterval;
1669 int est;
1670 int lst;
1671
1672 est = ests[v];
1673 lst = lsts[v];
1674
1675 /* compute number of possible start points */
1676 timeinterval = lst - est + 1;
1677
1678 /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1679 for( t = 0; t < timeinterval; ++t )
1680 {
1681 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1682 {
1683 ests[v] = est + t;
1684 break;
1685 }
1686 }
1687
1688 /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1689 for( t = timeinterval - 1; t >= 0; --t )
1690 {
1691 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1692 {
1693 lsts[v] = est + t;
1694 break;
1695 }
1696 }
1697 }
1698 (*solved) = FALSE;
1699 break;
1700
1706 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1707 return SCIP_INVALIDDATA;
1708 }
1709 }
1710
1711 /* release all variables */
1712 for( v = 0; v < njobs; ++v )
1713 {
1714 int timeinterval;
1715 int est;
1716 int lst;
1717
1718 est = ests[v];
1719 lst = lsts[v];
1720
1721 /* compute number of possible start points */
1722 timeinterval = lst - est + 1;
1723
1724 for( t = 0; t < timeinterval; ++t )
1725 {
1726 SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1727 }
1728 SCIPfreeBufferArray(subscip, &binvars[v]);
1729 }
1730
1731 SCIPfreeBufferArray(subscip, &binvars);
1732
1733 SCIP_CALL( SCIPfree(&subscip) );
1734
1735 return SCIP_OKAY;
1736}
1737#endif
1738
1739/**@} */
1740
1741/**@name Constraint handler data
1742 *
1743 * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1744 * handler.
1745 *
1746 * @{
1747 */
1748
1749/** creates constaint handler data for cumulative constraint handler */
1750static
1752 SCIP* scip, /**< SCIP data structure */
1753 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1754 SCIP_EVENTHDLR* eventhdlr /**< event handler */
1755 )
1756{
1757 /* create precedence constraint handler data */
1758 assert(scip != NULL);
1759 assert(conshdlrdata != NULL);
1760 assert(eventhdlr != NULL);
1761
1762 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1763
1764 /* set event handler for checking if bounds of start time variables are tighten */
1765 (*conshdlrdata)->eventhdlr = eventhdlr;
1766
1767 /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1768 (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1769
1770#ifdef SCIP_STATISTIC
1771 (*conshdlrdata)->nlbtimetable = 0;
1772 (*conshdlrdata)->nubtimetable = 0;
1773 (*conshdlrdata)->ncutofftimetable = 0;
1774 (*conshdlrdata)->nlbedgefinder = 0;
1775 (*conshdlrdata)->nubedgefinder = 0;
1776 (*conshdlrdata)->ncutoffedgefinder = 0;
1777 (*conshdlrdata)->ncutoffoverload = 0;
1778 (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1779
1780 (*conshdlrdata)->nirrelevantjobs = 0;
1781 (*conshdlrdata)->nalwaysruns = 0;
1782 (*conshdlrdata)->nremovedlocks = 0;
1783 (*conshdlrdata)->ndualfixs = 0;
1784 (*conshdlrdata)->ndecomps = 0;
1785 (*conshdlrdata)->ndualbranchs = 0;
1786 (*conshdlrdata)->nallconsdualfixs = 0;
1787 (*conshdlrdata)->naddedvarbounds = 0;
1788 (*conshdlrdata)->naddeddisjunctives = 0;
1789#endif
1790
1791 return SCIP_OKAY;
1792}
1793
1794/** frees constraint handler data for logic or constraint handler */
1795static
1797 SCIP* scip, /**< SCIP data structure */
1798 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1799 )
1800{
1801 assert(conshdlrdata != NULL);
1802 assert(*conshdlrdata != NULL);
1803
1804 SCIPfreeBlockMemory(scip, conshdlrdata);
1805}
1806
1807/**@} */
1808
1809
1810/**@name Constraint data methods
1811 *
1812 * @{
1813 */
1814
1815/** catches bound change events for all variables in transformed cumulative constraint */
1816static
1818 SCIP* scip, /**< SCIP data structure */
1819 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1820 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1821 )
1822{
1823 int v;
1824
1825 assert(scip != NULL);
1826 assert(consdata != NULL);
1827 assert(eventhdlr != NULL);
1828
1829 /* catch event for every single variable */
1830 for( v = 0; v < consdata->nvars; ++v )
1831 {
1832 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1833 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1834 }
1835
1836 return SCIP_OKAY;
1837}
1838
1839/** drops events for variable at given position */
1840static
1842 SCIP* scip, /**< SCIP data structure */
1843 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1844 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1845 int pos /**< array position of variable to catch bound change events for */
1846 )
1847{
1848 assert(scip != NULL);
1849 assert(consdata != NULL);
1850 assert(eventhdlr != NULL);
1851 assert(0 <= pos && pos < consdata->nvars);
1852 assert(consdata->vars[pos] != NULL);
1853
1854 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1855 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1856
1857 return SCIP_OKAY;
1858}
1859
1860/** drops bound change events for all variables in transformed linear constraint */
1861static
1863 SCIP* scip, /**< SCIP data structure */
1864 SCIP_CONSDATA* consdata, /**< linear constraint data */
1865 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1866 )
1867{
1868 int v;
1869
1870 assert(scip != NULL);
1871 assert(consdata != NULL);
1872
1873 /* drop event of every single variable */
1874 for( v = 0; v < consdata->nvars; ++v )
1875 {
1876 SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1877 }
1878
1879 return SCIP_OKAY;
1880}
1881
1882/** initialize variable lock data structure */
1883static
1885 SCIP_CONSDATA* consdata, /**< constraint data */
1886 SCIP_Bool locked /**< should the variable be locked? */
1887 )
1888{
1889 int nvars;
1890 int v;
1891
1892 nvars = consdata->nvars;
1893
1894 /* initialize locking arrays */
1895 for( v = 0; v < nvars; ++v )
1896 {
1897 consdata->downlocks[v] = locked;
1898 consdata->uplocks[v] = locked;
1899 }
1900}
1901
1902/** creates constraint data of cumulative constraint */
1903static
1905 SCIP* scip, /**< SCIP data structure */
1906 SCIP_CONSDATA** consdata, /**< pointer to consdata */
1907 SCIP_VAR** vars, /**< array of integer variables */
1908 SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1909 int* durations, /**< array containing corresponding durations */
1910 int* demands, /**< array containing corresponding demands */
1911 int nvars, /**< number of variables */
1912 int capacity, /**< available cumulative capacity */
1913 int hmin, /**< left bound of time axis to be considered (including hmin) */
1914 int hmax, /**< right bound of time axis to be considered (not including hmax) */
1915 SCIP_Bool check /**< is the corresponding constraint a check constraint */
1916 )
1917{
1918 int v;
1919
1920 assert(scip != NULL);
1921 assert(consdata != NULL);
1922 assert(vars != NULL || nvars > 0);
1923 assert(demands != NULL);
1924 assert(durations != NULL);
1925 assert(capacity >= 0);
1926 assert(hmin >= 0);
1927 assert(hmin < hmax);
1928
1929 /* create constraint data */
1930 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1931
1932 (*consdata)->hmin = hmin;
1933 (*consdata)->hmax = hmax;
1934
1935 (*consdata)->capacity = capacity;
1936 (*consdata)->demandrows = NULL;
1937 (*consdata)->demandrowssize = 0;
1938 (*consdata)->ndemandrows = 0;
1939 (*consdata)->scoverrows = NULL;
1940 (*consdata)->nscoverrows = 0;
1941 (*consdata)->scoverrowssize = 0;
1942 (*consdata)->bcoverrows = NULL;
1943 (*consdata)->nbcoverrows = 0;
1944 (*consdata)->bcoverrowssize = 0;
1945 (*consdata)->nvars = nvars;
1946 (*consdata)->varssize = nvars;
1947 (*consdata)->signature = 0;
1948 (*consdata)->validsignature = FALSE;
1949 (*consdata)->normalized = FALSE;
1950 (*consdata)->covercuts = FALSE;
1951 (*consdata)->propagated = FALSE;
1952 (*consdata)->varbounds = FALSE;
1953 (*consdata)->triedsolving = FALSE;
1954
1955 if( nvars > 0 )
1956 {
1957 assert(vars != NULL); /* for flexelint */
1958
1959 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1960 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1961 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1962 (*consdata)->linkingconss = NULL;
1963
1964 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1965 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1966
1967 /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
1968 initializeLocks(*consdata, check);
1969
1970 if( linkingconss != NULL )
1971 {
1972 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1973 }
1974
1975 /* transform variables, if they are not yet transformed */
1976 if( SCIPisTransformed(scip) )
1977 {
1978 SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1979
1980 /* get transformed variables and do NOT captures these */
1981 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1982
1983 /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1984 * been multi-aggregated
1985 */
1986 for( v = 0; v < nvars; ++v )
1987 {
1988 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1989 }
1990
1991 if( linkingconss != NULL )
1992 {
1993 /* get transformed constraints and captures these */
1994 SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1995
1996 for( v = 0; v < nvars; ++v )
1997 assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1998 }
1999 }
2000
2001#ifndef NDEBUG
2002 /* only binary and integer variables can be used in cumulative constraints
2003 * for fractional variable values, the constraint cannot be checked
2004 */
2005 for( v = 0; v < (*consdata)->nvars; ++v )
2006 assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
2007#endif
2008 }
2009 else
2010 {
2011 (*consdata)->vars = NULL;
2012 (*consdata)->downlocks = NULL;
2013 (*consdata)->uplocks = NULL;
2014 (*consdata)->demands = NULL;
2015 (*consdata)->durations = NULL;
2016 (*consdata)->linkingconss = NULL;
2017 }
2018
2019 /* initialize values for running propagation algorithms efficiently */
2020 (*consdata)->resstrength1 = -1.0;
2021 (*consdata)->resstrength2 = -1.0;
2022 (*consdata)->cumfactor1 = -1.0;
2023 (*consdata)->disjfactor1 = -1.0;
2024 (*consdata)->disjfactor2 = -1.0;
2025 (*consdata)->estimatedstrength = -1.0;
2026
2027 SCIPstatistic( (*consdata)->maxpeak = -1 );
2028
2029 return SCIP_OKAY;
2030}
2031
2032/** releases LP rows of constraint data and frees rows array */
2033static
2035 SCIP* scip, /**< SCIP data structure */
2036 SCIP_CONSDATA** consdata /**< constraint data */
2037 )
2038{
2039 int r;
2040
2041 assert(consdata != NULL);
2042 assert(*consdata != NULL);
2043
2044 for( r = 0; r < (*consdata)->ndemandrows; ++r )
2045 {
2046 assert((*consdata)->demandrows[r] != NULL);
2047 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2048 }
2049
2050 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2051
2052 (*consdata)->ndemandrows = 0;
2053 (*consdata)->demandrowssize = 0;
2054
2055 /* free rows of cover cuts */
2056 for( r = 0; r < (*consdata)->nscoverrows; ++r )
2057 {
2058 assert((*consdata)->scoverrows[r] != NULL);
2059 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2060 }
2061
2062 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2063
2064 (*consdata)->nscoverrows = 0;
2065 (*consdata)->scoverrowssize = 0;
2066
2067 for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2068 {
2069 assert((*consdata)->bcoverrows[r] != NULL);
2070 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2071 }
2072
2073 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2074
2075 (*consdata)->nbcoverrows = 0;
2076 (*consdata)->bcoverrowssize = 0;
2077
2078 (*consdata)->covercuts = FALSE;
2079
2080 return SCIP_OKAY;
2081}
2082
2083/** frees a cumulative constraint data */
2084static
2086 SCIP* scip, /**< SCIP data structure */
2087 SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2088 )
2089{
2090 int varssize;
2091 int nvars;
2092
2093 assert(consdata != NULL);
2094 assert(*consdata != NULL);
2095
2096 nvars = (*consdata)->nvars;
2097 varssize = (*consdata)->varssize;
2098
2099 if( varssize > 0 )
2100 {
2101 int v;
2102
2103 /* release and free the rows */
2104 SCIP_CALL( consdataFreeRows(scip, consdata) );
2105
2106 /* release the linking constraints if they were generated */
2107 if( (*consdata)->linkingconss != NULL )
2108 {
2109 for( v = nvars-1; v >= 0; --v )
2110 {
2111 assert((*consdata)->linkingconss[v] != NULL );
2112 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2113 }
2114
2115 SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2116 }
2117
2118 /* free arrays */
2119 SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2120 SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2121 SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2122 SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2123 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2124 }
2125
2126 /* free memory */
2127 SCIPfreeBlockMemory(scip, consdata);
2128
2129 return SCIP_OKAY;
2130}
2131
2132/** prints cumulative constraint to file stream */
2133static
2135 SCIP* scip, /**< SCIP data structure */
2136 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2137 FILE* file /**< output file (or NULL for standard output) */
2138 )
2139{
2140 int v;
2141
2142 assert(consdata != NULL);
2143
2144 /* print coefficients */
2145 SCIPinfoMessage( scip, file, "cumulative(");
2146
2147 for( v = 0; v < consdata->nvars; ++v )
2148 {
2149 assert(consdata->vars[v] != NULL);
2150 if( v > 0 )
2151 SCIPinfoMessage(scip, file, ", ");
2152 SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2153 SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2154 consdata->durations[v], consdata->demands[v]);
2155 }
2156 SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2157}
2158
2159/** deletes coefficient at given position from constraint data */
2160static
2162 SCIP* scip, /**< SCIP data structure */
2163 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2164 SCIP_CONS* cons, /**< knapsack constraint */
2165 int pos /**< position of coefficient to delete */
2166 )
2167{
2168 SCIP_CONSHDLR* conshdlr;
2169 SCIP_CONSHDLRDATA* conshdlrdata;
2170
2171 assert(scip != NULL);
2172 assert(consdata != NULL);
2173 assert(cons != NULL);
2176
2177 SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2178 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2179
2180 /* remove the rounding locks for the deleted variable */
2181 SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2182
2183 consdata->downlocks[pos] = FALSE;
2184 consdata->uplocks[pos] = FALSE;
2185
2186 if( consdata->linkingconss != NULL )
2187 {
2188 SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2189 }
2190
2191 /* get event handler */
2192 conshdlr = SCIPconsGetHdlr(cons);
2193 assert(conshdlr != NULL);
2194 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2195 assert(conshdlrdata != NULL);
2196 assert(conshdlrdata->eventhdlr != NULL);
2197
2198 /* drop events */
2199 SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2200
2201 SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2202 SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2203
2204 /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2205 * position
2206 */
2207 if( pos != consdata->nvars - 1 )
2208 {
2209 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2210 consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2211 consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2212 consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2213 consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2214
2215 if( consdata->linkingconss != NULL )
2216 {
2217 consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2218 }
2219 }
2220
2221 consdata->nvars--;
2222 consdata->validsignature = FALSE;
2223 consdata->normalized = FALSE;
2224
2225 return SCIP_OKAY;
2226}
2227
2228/** collect linking constraints for each integer variable */
2229static
2231 SCIP* scip, /**< SCIP data structure */
2232 SCIP_CONSDATA* consdata /**< pointer to consdata */
2233 )
2234{
2235 int nvars;
2236 int v;
2237
2238 assert(scip != NULL);
2239 assert(consdata != NULL);
2240
2241 nvars = consdata->nvars;
2242 assert(nvars > 0);
2243 assert(consdata->linkingconss == NULL);
2244
2245 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2246
2247 for( v = 0; v < nvars; ++v )
2248 {
2249 SCIP_CONS* cons;
2250 SCIP_VAR* var;
2251
2252 var = consdata->vars[v];
2253 assert(var != NULL);
2254
2255 SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2256
2257 /* create linking constraint if it does not exist yet */
2259 {
2260 char name[SCIP_MAXSTRLEN];
2261
2262 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2263
2264 /* creates and captures an linking constraint */
2265 SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2266 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2267 SCIP_CALL( SCIPaddCons(scip, cons) );
2268 consdata->linkingconss[v] = cons;
2269 }
2270 else
2271 {
2272 consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2273 SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2274 }
2275
2277 assert(consdata->linkingconss[v] != NULL);
2278 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2279 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2280 }
2281
2282 return SCIP_OKAY;
2283}
2284
2285/**@} */
2286
2287
2288/**@name Check methods
2289 *
2290 * @{
2291 */
2292
2293/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2294 * given solution is satisfied
2295 */
2296static
2298 SCIP* scip, /**< SCIP data structure */
2299 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2300 int nvars, /**< number of variables (jobs) */
2301 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2302 int* durations, /**< array containing corresponding durations */
2303 int* demands, /**< array containing corresponding demands */
2304 int capacity, /**< available cumulative capacity */
2305 int hmin, /**< left bound of time axis to be considered (including hmin) */
2306 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2307 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2308 SCIP_CONS* cons, /**< constraint which is checked */
2309 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2310 )
2311{
2312 int* startsolvalues; /* stores when each job is starting */
2313 int* endsolvalues; /* stores when each job ends */
2314 int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2315 int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2316
2317 int freecapacity;
2318 int curtime; /* point in time which we are just checking */
2319 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2320 int j;
2321
2322 SCIP_Real absviol;
2323 SCIP_Real relviol;
2324
2325 assert(scip != NULL);
2326 assert(violated != NULL);
2327
2328 (*violated) = FALSE;
2329
2330 if( nvars == 0 )
2331 return SCIP_OKAY;
2332
2333 assert(vars != NULL);
2334 assert(demands != NULL);
2335 assert(durations != NULL);
2336
2337 /* compute time points where we have to check whether capacity constraint is infeasible or not */
2340 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2342
2343 /* assign variables, start and endpoints to arrays */
2344 for ( j = 0; j < nvars; ++j )
2345 {
2346 int solvalue;
2347
2348 /* the constraint of the cumulative constraint handler should be called after the integrality check */
2350
2352
2353 /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2354 * jobs which start before hmin to hmin
2355 */
2356 startsolvalues[j] = MAX(solvalue, hmin);
2357 startindices[j] = j;
2358
2359 endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2360 endindices[j] = j;
2361 }
2362
2363 /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2364 * corresponding indices in the same way)
2365 */
2366 SCIPsortIntInt(startsolvalues, startindices, nvars);
2368
2369 endindex = 0;
2370 freecapacity = capacity;
2371 absviol = 0.0;
2372 relviol = 0.0;
2373
2374 /* check each start point of a job whether the capacity is kept or not */
2375 for( j = 0; j < nvars; ++j )
2376 {
2377 /* only check intervals [hmin,hmax) */
2379
2380 if( curtime >= hmax )
2381 break;
2382
2383 /* subtract all capacity needed up to this point */
2384 freecapacity -= demands[startindices[j]];
2385 while( j+1 < nvars && startsolvalues[j+1] == curtime )
2386 {
2387 j++;
2388 freecapacity -= demands[startindices[j]];
2389 }
2390
2391 /* free all capacity usages of jobs that are no longer running */
2393 {
2394 freecapacity += demands[endindices[endindex]];
2395 ++endindex;
2396 }
2397 assert(freecapacity <= capacity);
2398
2399 /* update absolute and relative violation */
2400 if( absviol < (SCIP_Real) (-freecapacity) )
2401 {
2403 relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2404 }
2405
2406 /* check freecapacity to be smaller than zero */
2408 {
2409 SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2410 (*violated) = TRUE;
2411
2412 if( printreason )
2413 {
2414 int i;
2415
2416 /* first state the violated constraints */
2417 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2418
2419 /* second state the reason */
2421 ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2422 curtime, capacity, capacity - freecapacity);
2423
2424 for( i = 0; i <= j; ++i )
2425 {
2426 if( startsolvalues[i] + durations[startindices[i]] > curtime )
2427 {
2428 SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2429 SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2430 demands[startindices[i]]);
2431 }
2432 }
2433 }
2434 break;
2435 }
2436 } /*lint --e{850}*/
2437
2438 /* update constraint violation in solution */
2439 if( sol != NULL )
2441
2442 /* free all buffer arrays */
2444 SCIPfreeBufferArray(scip, &startindices);
2447
2448 return SCIP_OKAY;
2449}
2450
2451/** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2452 * least zero or not. If not (*violated) is set to TRUE
2453 */
2454static
2456 SCIP* scip, /**< SCIP data structure */
2457 SCIP_CONS* cons, /**< constraint to be checked */
2458 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2459 SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2460 SCIP_Bool printreason /**< should the reason for the violation be printed? */
2461 )
2462{
2463 SCIP_CONSDATA* consdata;
2464
2465 assert(scip != NULL);
2466 assert(cons != NULL);
2467 assert(violated != NULL);
2468
2469 SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2470
2471 consdata = SCIPconsGetData(cons);
2472 assert(consdata != NULL);
2473
2474 /* check the cumulative condition */
2475 SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2476 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2477 violated, cons, printreason) );
2478
2479 return SCIP_OKAY;
2480}
2481
2482/**@} */
2483
2484/**@name Conflict analysis
2485 *
2486 * @{
2487 */
2488
2489/** resolves the propagation of the core time algorithm */
2490static
2492 SCIP* scip, /**< SCIP data structure */
2493 int nvars, /**< number of start time variables (activities) */
2494 SCIP_VAR** vars, /**< array of start time variables */
2495 int* durations, /**< array of durations */
2496 int* demands, /**< array of demands */
2497 int capacity, /**< cumulative capacity */
2498 int hmin, /**< left bound of time axis to be considered (including hmin) */
2499 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2500 SCIP_VAR* infervar, /**< inference variable */
2501 int inferdemand, /**< demand of the inference variable */
2502 int inferpeak, /**< time point which causes the propagation */
2503 int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2504 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2505 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2506 int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2507 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2508 )
2509{
2510 SCIP_VAR* var;
2511 SCIP_Bool* reported;
2512 int duration;
2513 int maxlst;
2514 int minect;
2515 int ect;
2516 int lst;
2517 int j;
2518
2520
2521 SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2523 assert(nvars > 0);
2524
2525 /* adjusted capacity */
2526 capacity -= inferdemand;
2527 maxlst = INT_MIN;
2528 minect = INT_MAX;
2529
2532
2533 /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2534 * inference peak and those where the current conflict bounds provide a core at the inference peak
2535 */
2536 for( j = 0; j < nvars && capacity >= 0; ++j )
2537 {
2538 var = vars[j];
2539 assert(var != NULL);
2540
2541 /* skip inference variable */
2542 if( var == infervar )
2543 continue;
2544
2545 duration = durations[j];
2546 assert(duration > 0);
2547
2548 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2553
2554 SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2556 SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2557
2560
2561 /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2562 * that job without adding it the explanation
2563 */
2564 if( inferpeak < ect && lst <= inferpeak )
2565 {
2566 capacity -= demands[j];
2567 reported[j] = TRUE;
2568
2569 maxlst = MAX(maxlst, lst);
2570 minect = MIN(minect, ect);
2571 assert(maxlst < minect);
2572
2573 if( explanation != NULL )
2574 explanation[j] = TRUE;
2575
2576 continue;
2577 }
2578
2579 /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2580 * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2581 * not part of the conflict yet we get the global bounds back.
2582 */
2585
2586 /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2587 * of that job without and collect the job as part of the explanation
2588 *
2589 * @note we do not need to reported that job to SCIP since the required bounds are already reported
2590 */
2591 if( inferpeak < ect && lst <= inferpeak )
2592 {
2593 capacity -= demands[j];
2594 reported[j] = TRUE;
2595
2596 maxlst = MAX(maxlst, lst);
2597 minect = MIN(minect, ect);
2598 assert(maxlst < minect);
2599
2600 if( explanation != NULL )
2601 explanation[j] = TRUE;
2602 }
2603 }
2604
2605 if( capacity >= 0 )
2606 {
2607 int* cands;
2608 int* canddemands;
2609 int ncands;
2610 int c;
2611
2614 ncands = 0;
2615
2616 /* collect all cores of the variables which lay in the considered time window except the inference variable */
2617 for( j = 0; j < nvars; ++j )
2618 {
2619 var = vars[j];
2620 assert(var != NULL);
2621
2622 /* skip inference variable */
2623 if( var == infervar || reported[j] )
2624 continue;
2625
2626 duration = durations[j];
2627 assert(duration > 0);
2628
2629 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2634
2635 /* collect local core information */
2636 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2638
2639 SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2641 SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2642
2643 /* check if the inference peak is part of the core */
2644 if( inferpeak < ect && lst <= inferpeak )
2645 {
2646 cands[ncands] = j;
2647 canddemands[ncands] = demands[j];
2648 ncands++;
2649
2650 capacity -= demands[j];
2651 }
2652 }
2653
2654 /* sort candidates indices w.r.t. their demands */
2655 SCIPsortDownIntInt(canddemands, cands, ncands);
2656
2657 assert(capacity < 0);
2658 assert(ncands > 0);
2659
2660 /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2661 while( capacity + canddemands[ncands-1] < 0 )
2662 {
2663 ncands--;
2664 capacity += canddemands[ncands];
2665 assert(ncands > 0);
2666 }
2667
2668 /* compute the size (number of time steps) of the job cores */
2669 for( c = 0; c < ncands; ++c )
2670 {
2671 var = vars[cands[c]];
2672 assert(var != NULL);
2673
2674 duration = durations[cands[c]];
2675
2676 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2678
2679 maxlst = MAX(maxlst, lst);
2680 minect = MIN(minect, ect);
2681 assert(maxlst < minect);
2682 }
2683
2684 SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2687
2688 /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2689 if( relaxedpeak < inferpeak )
2690 {
2692 }
2693 else if( relaxedpeak > inferpeak )
2694 {
2696 }
2697 assert(inferpeak >= hmin);
2698 assert(inferpeak < hmax);
2701
2702 /* post all necessary bound changes */
2703 for( c = 0; c < ncands; ++c )
2704 {
2705 var = vars[cands[c]];
2706 assert(var != NULL);
2707
2708 if( usebdwidening )
2709 {
2710 duration = durations[cands[c]];
2711
2712 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2713 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2714 }
2715 else
2716 {
2717 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2718 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2719 }
2720
2721 if( explanation != NULL )
2722 explanation[cands[c]] = TRUE;
2723 }
2724
2726 SCIPfreeBufferArray(scip, &cands);
2727 }
2728
2730
2731 if( provedpeak != NULL )
2733
2734 return SCIP_OKAY;
2735}
2736
2737#if 0
2738/** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2739 * energy in total and for bound change is enough
2740 */
2741static
2743 SCIP* scip, /**< SCIP data structure */
2744 int nvars, /**< number of start time variables (activities) */
2745 SCIP_VAR** vars, /**< array of start time variables */
2746 int* durations, /**< array of durations */
2747 int hmin, /**< left bound of time axis to be considered (including hmin) */
2748 int hmax, /**< right bound of time axis to be considered (not including hmax) */
2749 SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2750 INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2751 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2752 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2753 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2754 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2755 )
2756{
2757 int est;
2758 int lct;
2759 int j;
2760
2761 /* ???????????????????? do bound widening */
2762
2763 assert(scip != NULL);
2764 assert(nvars > 0);
2766
2767 SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2768
2769 if( boundtype == SCIP_BOUNDTYPE_LOWER )
2770 {
2772 }
2773 else
2774 {
2776 }
2777
2778 est = inferInfoGetData1(inferinfo);
2779 lct = inferInfoGetData2(inferinfo);
2780 assert(est < lct);
2781
2782 /* collect the energies of all variables in [est_omega, lct_omega] */
2783 for( j = 0; j < nvars; ++j )
2784 {
2785 SCIP_VAR* var;
2786 SCIP_Bool left;
2787 SCIP_Bool right;
2788 int duration;
2789 int lb;
2790 int ub;
2791
2792 var = vars[j];
2793 assert(var != NULL);
2794
2795 if( var == infervar )
2796 {
2797 if( explanation != NULL )
2798 explanation[j] = TRUE;
2799
2800 continue;
2801 }
2802
2805
2806 duration = durations[j];
2807 assert(duration > 0);
2808
2809 /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2810 * since we use adjusted jobs during the propagation
2811 */
2812 left = (est == hmin && lb + duration > hmin) || lb >= est;
2813
2814 /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2815 * since we use adjusted jobs during the propagation
2816 */
2817 right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2818
2819 /* store all jobs running in [est_omega; lct_omega] */
2820 if( left && right )
2821 {
2822 /* check if bound widening should be used */
2823 if( usebdwidening )
2824 {
2825 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2826 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2827 }
2828 else
2829 {
2830 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2831 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2832 }
2833
2834 if( explanation != NULL )
2835 explanation[j] = TRUE;
2836 }
2837 }
2838
2839 return SCIP_OKAY;
2840}
2841#endif
2842
2843/** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2844static
2846 int begin, /**< begin of the times interval */
2847 int end, /**< end of time interval */
2848 int est, /**< earliest start time */
2849 int lst, /**< latest start time */
2850 int duration /**< duration of the job */
2851 )
2852{
2853 int left;
2854 int right;
2855 int ect;
2856 int lct;
2857
2858 ect = est + duration;
2859 lct = lst + duration;
2860
2861 /* check if job runs completely within [begin,end) */
2863 return duration;
2864
2866
2867 left = ect - begin;
2868 assert(left > 0);
2869
2870 right = end - lst;
2871 assert(right > 0);
2872
2873 return MIN3(left, right, end - begin);
2874}
2875
2876/** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2877 * reason
2878 *
2879 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2880 */
2881static
2883 SCIP* scip, /**< SCIP data structure */
2884 int nvars, /**< number of start time variables (activities) */
2885 SCIP_VAR** vars, /**< array of start time variables */
2886 int* durations, /**< array of durations */
2887 int* demands, /**< array of demands */
2888 int capacity, /**< capacity of the cumulative condition */
2889 int begin, /**< begin of the time window */
2890 int end, /**< end of the time window */
2891 SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2892 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2893 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2894 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2895 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2896 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2897 )
2898{
2899 int* locenergies;
2900 int* overlaps;
2901 int* idxs;
2902
2903 SCIP_Longint requiredenergy;
2904 int v;
2905
2909
2910 /* energy which needs be explained */
2911 requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2912
2913 SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2914
2915 /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2916 * takes
2917 */
2918 for( v = 0; v < nvars; ++v )
2919 {
2920 SCIP_VAR* var;
2921 int glbenergy;
2922 int duration;
2923 int demand;
2924 int est;
2925 int lst;
2926
2927 var = vars[v];
2928 assert(var != NULL);
2929
2930 locenergies[v] = 0;
2931 overlaps[v] = 0;
2932 idxs[v] = v;
2933
2934 demand = demands[v];
2935 assert(demand > 0);
2936
2937 duration = durations[v];
2938 assert(duration > 0);
2939
2940 /* check if the variable equals the inference variable (the one which was propagated) */
2941 if( infervar == var )
2942 {
2943 int overlap;
2944 int right;
2945 int left;
2946
2947 assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2948
2949 SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2951 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2952
2953 /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2954 * which is necessary from the inference variable
2955 */
2956 if( boundtype == SCIP_BOUNDTYPE_UPPER )
2957 {
2958 int lct;
2959
2960 /* get the latest start time of the infer start time variable before the propagation took place */
2962
2963 /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2964 * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2965 * scheduled w.r.t. its latest start time
2966 */
2967 assert(lst < end);
2968
2969 /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2970 * interval (before the propagation)
2971 */
2972 right = MIN3(end - lst, end - begin, duration);
2973
2974 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2975 assert(right > 0);
2976
2977 lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2978 assert(begin <= lct);
2979 assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2980
2981 /* compute the overlap of the job after the propagation but considering the relaxed bound */
2982 left = MIN(lct - begin + 1, end - begin);
2983 assert(left > 0);
2984
2985 /* compute the minimum overlap; */
2986 overlap = MIN(left, right);
2987 assert(overlap > 0);
2988 assert(overlap <= end - begin);
2989 assert(overlap <= duration);
2990
2991 if( usebdwidening )
2992 {
2993 assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2994 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2995 }
2996 else
2997 {
2998 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2999 }
3000 }
3001 else
3002 {
3003 int ect;
3004
3005 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3006
3007 /* get the earliest completion time of the infer start time variable before the propagation took place */
3008 ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
3009
3010 /* the earliest start time of the inference start time variable before the propagation needs to be larger as
3011 * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
3012 * the job is scheduled w.r.t. its earliest start time
3013 */
3014 assert(ect > begin);
3015
3016 /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
3017 * interval (before the propagation)
3018 */
3019 left = MIN3(ect - begin, end - begin, duration);
3020
3021 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
3022 assert(left > 0);
3023
3025 assert(end >= est);
3026 assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
3027
3028 /* compute the overlap of the job after the propagation but considering the relaxed bound */
3029 right = MIN(end - est + 1, end - begin);
3030 assert(right > 0);
3031
3032 /* compute the minimum overlap */
3033 overlap = MIN(left, right);
3034 assert(overlap > 0);
3035 assert(overlap <= end - begin);
3036 assert(overlap <= duration);
3037
3038 if( usebdwidening )
3039 {
3040 assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3041 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3042 }
3043 else
3044 {
3045 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3046 }
3047 }
3048
3049 /* subtract the amount of energy which is available due to the overlap of the inference start time */
3050 requiredenergy -= (SCIP_Longint) overlap * demand;
3051
3052 if( explanation != NULL )
3053 explanation[v] = TRUE;
3054
3055 continue;
3056 }
3057
3058 /* global time points */
3061
3062 glbenergy = 0;
3063
3064 /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3065 * time window
3066 */
3067 if( est + duration > begin && lst < end )
3068 {
3069 /* evaluated global contribution */
3070 glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3071
3072 /* remove the globally available energy form the required energy */
3074
3075 if( explanation != NULL )
3076 explanation[v] = TRUE;
3077 }
3078
3079 /* local time points */
3082
3083 /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3084 * time window
3085 */
3086 if( est + duration > begin && lst < end )
3087 {
3088 overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3089
3090 /* evaluated additionally local energy contribution */
3091 locenergies[v] = overlaps[v] * demand - glbenergy;
3092 assert(locenergies[v] >= 0);
3093 }
3094 }
3095
3096 /* sort the variable contributions w.r.t. additional local energy contributions */
3098
3099 /* add local energy contributions until an overload is implied */
3100 for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3101 {
3102 SCIP_VAR* var;
3103 int duration;
3104 int overlap;
3105 int relaxlb;
3106 int relaxub;
3107 int idx;
3108
3109 idx = idxs[v];
3110 assert(idx >= 0 && idx < nvars);
3111
3112 var = vars[idx];
3113 assert(var != NULL);
3114 assert(var != infervar);
3115
3116 duration = durations[idx];
3117 assert(duration > 0);
3118
3119 overlap = overlaps[v];
3120 assert(overlap > 0);
3121
3123
3124 if( requiredenergy < -1 )
3125 {
3126 int demand;
3127
3128 demand = demands[idx];
3129 assert(demand > 0);
3130
3131 overlap += (int)((requiredenergy + 1) / demand);
3132
3133#ifndef NDEBUG
3135 requiredenergy -= (SCIP_Longint) overlap * demand;
3137#endif
3138 }
3139 assert(overlap > 0);
3140
3141 relaxlb = begin - duration + overlap;
3142 relaxub = end - overlap;
3143
3144 SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3149 relaxlb, relaxub, demands[idx], duration);
3150
3151 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3152 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3153
3154 if( explanation != NULL )
3155 explanation[idx] = TRUE;
3156 }
3157
3159
3163
3164 return SCIP_OKAY;
3165}
3166
3167/** resolve propagation w.r.t. the cumulative condition */
3168static
3170 SCIP* scip, /**< SCIP data structure */
3171 int nvars, /**< number of start time variables (activities) */
3172 SCIP_VAR** vars, /**< array of start time variables */
3173 int* durations, /**< array of durations */
3174 int* demands, /**< array of demands */
3175 int capacity, /**< cumulative capacity */
3176 int hmin, /**< left bound of time axis to be considered (including hmin) */
3177 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3178 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3179 INFERINFO inferinfo, /**< the user information */
3180 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3181 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3182 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3183 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3184 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3185 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3186 )
3187{
3188 switch( inferInfoGetProprule(inferinfo) )
3189 {
3191 {
3192 int inferdemand;
3193 int inferduration;
3194 int inferpos;
3195 int inferpeak;
3196 int relaxedpeak;
3197 int provedpeak;
3198
3199 /* get the position of the inferred variable in the vars array */
3200 inferpos = inferInfoGetData1(inferinfo);
3201 if( inferpos >= nvars || vars[inferpos] != infervar )
3202 {
3203 /* find inference variable in constraint */
3204 for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3205 {}
3206 }
3209
3210 inferdemand = demands[inferpos];
3211 inferduration = durations[inferpos];
3212
3213 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3214 {
3215 /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3216 * the inference variable
3217 */
3219
3220 SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3223
3224 /* get the inference peak that the time point which lead to the that propagtion */
3225 inferpeak = inferInfoGetData2(inferinfo);
3226 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3227 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3228 */
3231
3232 /* make sure that the relaxed peak is part of the effective horizon */
3233 relaxedpeak = MIN(relaxedpeak, hmax-1);
3234
3235 /* make sure that relaxed peak is not larger than the infer peak
3236 *
3237 * This can happen in case the variable is not an active variable!
3238 */
3241 assert(relaxedpeak >= hmin);
3242 }
3243 else
3244 {
3245 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3246
3247 SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3250
3251 /* get the time interval where the job could not be scheduled */
3252 inferpeak = inferInfoGetData2(inferinfo);
3253 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3254 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3255 */
3258
3259 /* make sure that the relaxed peak is part of the effective horizon */
3260 relaxedpeak = MAX(relaxedpeak, hmin);
3261
3262 /* make sure that relaxed peak is not larger than the infer peak
3263 *
3264 * This can happen in case the variable is not an active variable!
3265 */
3267 assert(relaxedpeak < hmax);
3268 }
3269
3270 /* resolves the propagation of the core time algorithm */
3271 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3272 infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3273
3274 if( boundtype == SCIP_BOUNDTYPE_UPPER )
3275 {
3276 if( usebdwidening )
3277 {
3279 }
3280 else
3281 {
3282 /* old upper bound of variable itself is part of the explanation */
3284 }
3285 }
3286 else
3287 {
3288 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3289
3290 if( usebdwidening )
3291 {
3292 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3293 }
3294 else
3295 {
3296 /* old lower bound of variable itself is part of the explanation */
3298 }
3299 }
3300
3301 if( explanation != NULL )
3303
3304 break;
3305 }
3307 case PROPRULE_3_TTEF:
3308 {
3309 int begin;
3310 int end;
3311
3312 begin = inferInfoGetData1(inferinfo);
3313 end = inferInfoGetData2(inferinfo);
3314 assert(begin < end);
3315
3316 begin = MAX(begin, hmin);
3317 end = MIN(end, hmax);
3318
3319 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3320 begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3321
3322 break;
3323 }
3324
3325 case PROPRULE_0_INVALID:
3326 default:
3327 SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3328 SCIPABORT();
3329 return SCIP_INVALIDDATA; /*lint !e527*/
3330 }
3331
3332 (*result) = SCIP_SUCCESS;
3333
3334 return SCIP_OKAY;
3335}
3336
3337/**@} */
3338
3339
3340/**@name Enforcement methods
3341 *
3342 * @{
3343 */
3344
3345/** apply all fixings which are given by the alternative bounds */
3346static
3348 SCIP* scip, /**< SCIP data structure */
3349 SCIP_VAR** vars, /**< array of active variables */
3350 int nvars, /**< number of active variables */
3351 int* alternativelbs, /**< alternative lower bounds */
3352 int* alternativeubs, /**< alternative lower bounds */
3353 int* downlocks, /**< number of constraints with down lock participating by the computation */
3354 int* uplocks, /**< number of constraints with up lock participating by the computation */
3355 SCIP_Bool* branched /**< pointer to store if a branching was applied */
3356 )
3357{
3358 int v;
3359
3360 for( v = 0; v < nvars; ++v )
3361 {
3362 SCIP_VAR* var;
3363 SCIP_Real objval;
3364
3365 var = vars[v];
3366 assert(var != NULL);
3367
3369
3371 {
3372 int ub;
3373
3375
3376 if( alternativelbs[v] <= ub )
3377 {
3379 (*branched) = TRUE;
3380
3381 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3383
3384 return SCIP_OKAY;
3385 }
3386 }
3387
3389 {
3390 int lb;
3391
3393
3394 if( alternativeubs[v] >= lb )
3395 {
3397 (*branched) = TRUE;
3398
3399 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3401
3402 return SCIP_OKAY;
3403 }
3404 }
3405 }
3406
3407 return SCIP_OKAY;
3408}
3409
3410/** remove the capacity requirments for all job which start at the curtime */
3411static
3413 SCIP_CONSDATA* consdata, /**< constraint data */
3414 int curtime, /**< current point in time */
3415 int* starttimes, /**< array of start times */
3416 int* startindices, /**< permutation with respect to the start times */
3417 int* freecapacity, /**< pointer to store the resulting free capacity */
3418 int* idx, /**< pointer to index in start time array */
3419 int nvars /**< number of vars in array of starttimes and startindices */
3420 )
3421{
3422#if defined SCIP_DEBUG && !defined NDEBUG
3423 int oldidx;
3424
3425 assert(idx != NULL);
3426 oldidx = *idx;
3427#else
3428 assert(idx != NULL);
3429#endif
3430
3434 assert(starttimes[*idx] == curtime);
3435 assert(consdata->demands != NULL);
3436 assert(freecapacity != idx);
3437
3438 /* subtract all capacity needed up to this point */
3439 (*freecapacity) -= consdata->demands[startindices[*idx]];
3440
3441 while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3442 {
3443 ++(*idx);
3444 (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3445 assert(freecapacity != idx);
3446 }
3447#ifdef SCIP_DEBUG
3448 assert(oldidx <= *idx);
3449#endif
3450}
3451
3452/** add the capacity requirments for all job which end at the curtime */
3453static
3455 SCIP_CONSDATA* consdata, /**< constraint data */
3456 int curtime, /**< current point in time */
3457 int* endtimes, /**< array of end times */
3458 int* endindices, /**< permutation with rspect to the end times */
3459 int* freecapacity, /**< pointer to store the resulting free capacity */
3460 int* idx, /**< pointer to index in end time array */
3461 int nvars /**< number of vars in array of starttimes and startindices */
3462 )
3463{
3464#if defined SCIP_DEBUG && !defined NDEBUG
3465 int oldidx;
3466 oldidx = *idx;
3467#endif
3468
3469 /* free all capacity usages of jobs the are no longer running */
3470 while( endtimes[*idx] <= curtime && *idx < nvars)
3471 {
3472 (*freecapacity) += consdata->demands[endindices[*idx]];
3473 ++(*idx);
3474 }
3475
3476#ifdef SCIP_DEBUG
3477 assert(oldidx <= *idx);
3478#endif
3479}
3480
3481/** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3482static
3484 SCIP* scip, /**< SCIP data structure */
3485 SCIP_CONSDATA* consdata, /**< constraint handler data */
3486 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3487 int* timepoint /**< pointer to store the time point of the peak */
3488 )
3489{
3490 int* starttimes; /* stores when each job is starting */
3491 int* endtimes; /* stores when each job ends */
3492 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3493 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3494
3495 int nvars; /* number of activities for this constraint */
3496 int freecapacity; /* remaining capacity */
3497 int curtime; /* point in time which we are just checking */
3498 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3499
3500 int hmin;
3501 int hmax;
3502
3503 int j;
3504
3505 assert(consdata != NULL);
3506
3507 nvars = consdata->nvars;
3508 assert(nvars > 0);
3509
3510 *timepoint = consdata->hmax;
3511
3512 assert(consdata->vars != NULL);
3513
3516 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3518
3519 /* create event point arrays */
3520 createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3521 starttimes, endtimes, startindices, endindices);
3522
3523 endindex = 0;
3524 freecapacity = consdata->capacity;
3525 hmin = consdata->hmin;
3526 hmax = consdata->hmax;
3527
3528 /* check each startpoint of a job whether the capacity is kept or not */
3529 for( j = 0; j < nvars; ++j )
3530 {
3531 curtime = starttimes[j];
3532 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3533
3534 if( curtime >= hmax )
3535 break;
3536
3537 /* remove the capacity requirments for all job which start at the curtime */
3538 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3539
3540 /* add the capacity requirments for all job which end at the curtime */
3542
3544 assert(endindex <= nvars);
3545
3546 /* endindex - points to the next job which will finish */
3547 /* j - points to the last job that has been released */
3548
3549 /* if free capacity is smaller than zero, then add branching candidates */
3551 {
3552 *timepoint = curtime;
3553 break;
3554 }
3555 } /*lint --e{850}*/
3556
3557 /* free all buffer arrays */
3559 SCIPfreeBufferArray(scip, &startindices);
3562
3563 return SCIP_OKAY;
3564}
3565
3566/** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3567static
3569 SCIP* scip, /**< SCIP data structure */
3570 SCIP_CONS** conss, /**< constraints to be processed */
3571 int nconss, /**< number of constraints */
3572 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3573 int* nbranchcands /**< pointer to store the number of branching variables */
3574 )
3575{
3577 int c;
3578
3579 assert(scip != NULL);
3580 assert(conss != NULL);
3581
3582 /* create a hash table */
3585
3586 assert(scip != NULL);
3587 assert(conss != NULL);
3588
3589 for( c = 0; c < nconss; ++c )
3590 {
3591 SCIP_CONS* cons;
3592 SCIP_CONSDATA* consdata;
3593
3594 int curtime;
3595 int j;
3596
3597 cons = conss[c];
3598 assert(cons != NULL);
3599
3600 if( !SCIPconsIsActive(cons) )
3601 continue;
3602
3603 consdata = SCIPconsGetData(cons);
3604 assert(consdata != NULL);
3605
3606 /* get point in time when capacity is exceeded */
3607 SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3608
3609 if( curtime < consdata->hmin || curtime >= consdata->hmax )
3610 continue;
3611
3612 /* report all variables that are running at that point in time */
3613 for( j = 0; j < consdata->nvars; ++j )
3614 {
3615 SCIP_VAR* var;
3616 int lb;
3617 int ub;
3618
3619 var = consdata->vars[j];
3620 assert(var != NULL);
3621
3622 /* check if the variable was already added */
3624 continue;
3625
3628
3629 if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3630 {
3631 SCIP_Real solval;
3632 SCIP_Real score;
3633
3634 solval = SCIPgetSolVal(scip, sol, var);
3635 score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3636
3637 SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3638 SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3639 (*nbranchcands)++;
3640
3642 }
3643 }
3644 }
3645
3647
3648 SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3649
3650 return SCIP_OKAY;
3651}
3652
3653/** enforcement of an LP, pseudo, or relaxation solution */
3654static
3656 SCIP* scip, /**< SCIP data structure */
3657 SCIP_CONS** conss, /**< constraints to be processed */
3658 int nconss, /**< number of constraints */
3659 SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3660 SCIP_Bool branch, /**< should branching candidates be collected */
3661 SCIP_RESULT* result /**< pointer to store the result */
3662 )
3663{
3664 if( branch )
3665 {
3666 int nbranchcands;
3667
3668 nbranchcands = 0;
3669 SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3670
3671 if( nbranchcands > 0 )
3672 (*result) = SCIP_INFEASIBLE;
3673 }
3674 else
3675 {
3676 SCIP_Bool violated;
3677 int c;
3678
3679 violated = FALSE;
3680
3681 /* first check if a constraints is violated */
3682 for( c = 0; c < nconss && !violated; ++c )
3683 {
3684 SCIP_CONS* cons;
3685
3686 cons = conss[c];
3687 assert(cons != NULL);
3688
3689 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3690 }
3691
3692 if( violated )
3693 (*result) = SCIP_INFEASIBLE;
3694 }
3695
3696 return SCIP_OKAY;
3697}
3698
3699/**@} */
3700
3701/**@name Propagation
3702 *
3703 * @{
3704 */
3705
3706/** check if cumulative constraint is independently of all other constraints */
3707static
3709 SCIP_CONS* cons /**< cumulative constraint */
3710 )
3711{
3712 SCIP_CONSDATA* consdata;
3713 SCIP_VAR** vars;
3714 SCIP_Bool* downlocks;
3715 SCIP_Bool* uplocks;
3716 int nvars;
3717 int v;
3718
3719 consdata = SCIPconsGetData(cons);
3720 assert(consdata != NULL);
3721
3722 nvars = consdata->nvars;
3723 vars = consdata->vars;
3724 downlocks = consdata->downlocks;
3725 uplocks = consdata->uplocks;
3726
3727 /* check if the cumulative constraint has the only locks on the involved variables */
3728 for( v = 0; v < nvars; ++v )
3729 {
3730 SCIP_VAR* var;
3731
3732 var = vars[v];
3733 assert(var != NULL);
3734
3735 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3736 || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3737 return FALSE;
3738 }
3739
3740 return TRUE;
3741}
3742
3743/** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3744 * (dual reductions)
3745 */
3746static
3748 SCIP* scip, /**< SCIP data structure */
3749 SCIP_CONS* cons, /**< cumulative constraint */
3750 SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3751 int* nchgbds, /**< pointer to store the number changed variable bounds */
3752 int* nfixedvars, /**< pointer to count number of fixings */
3753 int* ndelconss, /**< pointer to count number of deleted constraints */
3754 SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3755 SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3756 )
3757{
3758 SCIP_CONSDATA* consdata;
3759 SCIP_VAR** vars;
3760 SCIP_Real* objvals;
3761 SCIP_Real* lbs;
3762 SCIP_Real* ubs;
3763 SCIP_Real timelimit;
3764 SCIP_Real memorylimit;
3765 SCIP_Bool solved;
3766 SCIP_Bool error;
3767
3768 int ncheckconss;
3769 int nvars;
3770 int v;
3771
3772 assert(scip != NULL);
3775
3776 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3777 * would/could end in an implication which can lead to cutoff of the/all optimal solution
3778 */
3780 return SCIP_OKAY;
3781
3782 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3783 * use the locks to decide for a dual reduction using this constraint;
3784 */
3785 if( !SCIPconsIsChecked(cons) )
3786 return SCIP_OKAY;
3787
3788 ncheckconss = SCIPgetNCheckConss(scip);
3789
3790 /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3791 * presolved problem do nothing execpt to change the parameter settings
3792 */
3793 if( ncheckconss == 1 )
3794 {
3795 /* shrink the minimal maximum value for the conflict length */
3796 SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3797
3798 /* use only first unique implication point */
3799 SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3800
3801 /* do not use reconversion conflicts */
3802 SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3803
3804 /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3805 SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3806
3807 /* increase the number of conflicts which induce a restart */
3808 SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3809
3810 /* weight the variable which made into a conflict */
3811 SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3812
3813 /* do not check pseudo solution (for performance reasons) */
3814 SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3815
3816 /* use value based history to detect a reasonable branching point */
3817 SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3818
3819 /* turn of LP relaxation */
3820 SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3821
3822 /* prefer the down branch in case the value based history does not suggest something */
3823 SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3824
3825 /* accept any bound change */
3826 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3827
3828 /* allow for at most 10 restart, after that the value based history should be reliable */
3829 SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3830
3831 /* set priority for depth first search to highest possible value */
3832 SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3833
3834 return SCIP_OKAY;
3835 }
3836
3837 consdata = SCIPconsGetData(cons);
3838 assert(consdata != NULL);
3839
3840 /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3841 * fail on the first place
3842 */
3843 if( consdata->triedsolving )
3844 return SCIP_OKAY;
3845
3846 /* check if constraint is independently */
3847 if( !isConsIndependently(cons) )
3848 return SCIP_OKAY;
3849
3850 /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3851 * constraint is deleted; otherwise, we want to ensure that we do not try that again
3852 */
3853 consdata->triedsolving = TRUE;
3854
3855 SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3858
3859 nvars = consdata->nvars;
3860 vars = consdata->vars;
3861
3865
3866 for( v = 0; v < nvars; ++v )
3867 {
3868 SCIP_VAR* var;
3869
3870 /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3871 * array
3872 */
3873 var = vars[v];
3874 assert(var != NULL);
3875
3876 lbs[v] = SCIPvarGetLbLocal(var);
3877 ubs[v] = SCIPvarGetUbLocal(var);
3878
3880 }
3881
3882 /* check whether there is enough time and memory left */
3883 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3884 if( !SCIPisInfinity(scip, timelimit) )
3885 timelimit -= SCIPgetSolvingTime(scip);
3886 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3887
3888 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3889 if( !SCIPisInfinity(scip, memorylimit) )
3890 {
3891 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3892 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3893 }
3894
3895 /* solve the cumulative condition separately */
3896 SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3897 consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3898
3899 if( !(*cutoff) && !(*unbounded) && !error )
3900 {
3901 SCIP_Bool infeasible;
3902 SCIP_Bool tightened;
3903 SCIP_Bool allfixed;
3904
3905 allfixed = TRUE;
3906
3907 for( v = 0; v < nvars; ++v )
3908 {
3909 /* check if variable is fixed */
3910 if( lbs[v] + 0.5 > ubs[v] )
3911 {
3912 SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3913 assert(!infeasible);
3914
3915 if( tightened )
3916 {
3917 (*nfixedvars)++;
3918 consdata->triedsolving = FALSE;
3919 }
3920 }
3921 else
3922 {
3923 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3924 assert(!infeasible);
3925
3926 if( tightened )
3927 {
3928 (*nchgbds)++;
3929 consdata->triedsolving = FALSE;
3930 }
3931
3932 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3933 assert(!infeasible);
3934
3935 if( tightened )
3936 {
3937 (*nchgbds)++;
3938 consdata->triedsolving = FALSE;
3939 }
3940
3941 allfixed = FALSE;
3942 }
3943 }
3944
3945 /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3946 if( allfixed )
3947 {
3949 (*ndelconss)++;
3950 }
3951 }
3952
3956
3957 return SCIP_OKAY;
3958}
3959
3960/** start conflict analysis to analysis the core insertion which is infeasible */
3961static
3963 SCIP* scip, /**< SCIP data structure */
3964 int nvars, /**< number of start time variables (activities) */
3965 SCIP_VAR** vars, /**< array of start time variables */
3966 int* durations, /**< array of durations */
3967 int* demands, /**< array of demands */
3968 int capacity, /**< cumulative capacity */
3969 int hmin, /**< left bound of time axis to be considered (including hmin) */
3970 int hmax, /**< right bound of time axis to be considered (not including hmax) */
3971 SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3972 int inferduration, /**< duration of the start time variable */
3973 int inferdemand, /**< demand of the start time variable */
3974 int inferpeak, /**< profile preak which causes the infeasibilty */
3975 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3976 SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3977 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3978 )
3979{
3980 SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3981 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3983
3984 /* initialize conflict analysis if conflict analysis is applicable */
3986 {
3988
3989 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3991
3992 SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3993
3994 /* add both bound of the inference variable since these biuld the core which we could not inserted */
3995 if( usebdwidening )
3996 {
3999 }
4000 else
4001 {
4004 }
4005
4006 *initialized = TRUE;
4007 }
4008
4009 return SCIP_OKAY;
4010}
4011
4012/** We are using the core resource profile which contains all core except the one of the start time variable which we
4013 * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
4014 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4015 * analysis
4016 */
4017static
4019 SCIP* scip, /**< SCIP data structure */
4020 int nvars, /**< number of start time variables (activities) */
4021 SCIP_VAR** vars, /**< array of start time variables */
4022 int* durations, /**< array of durations */
4023 int* demands, /**< array of demands */
4024 int capacity, /**< cumulative capacity */
4025 int hmin, /**< left bound of time axis to be considered (including hmin) */
4026 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4027 SCIP_CONS* cons, /**< constraint which is propagated */
4028 SCIP_PROFILE* profile, /**< resource profile */
4029 int idx, /**< position of the variable to propagate */
4030 int* nchgbds, /**< pointer to store the number of bound changes */
4031 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
4032 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4033 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4034 SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4035 )
4036{
4037 SCIP_VAR* var;
4038 int ntimepoints;
4039 int duration;
4040 int demand;
4041 int peak;
4042 int newlb;
4043 int est;
4044 int lst;
4045 int pos;
4046
4047 var = vars[idx];
4048 assert(var != NULL);
4049
4050 duration = durations[idx];
4051 assert(duration > 0);
4052
4053 demand = demands[idx];
4054 assert(demand > 0);
4055
4058 ntimepoints = SCIPprofileGetNTimepoints(profile);
4059
4060 /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4061 * load which we have at the earliest start time (lower bound)
4062 */
4063 (void) SCIPprofileFindLeft(profile, est, &pos);
4064
4065 SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4066
4067 /* we now trying to move the earliest start time in steps of at most "duration" length */
4068 do
4069 {
4070 INFERINFO inferinfo;
4071 SCIP_Bool tightened;
4072 int ect;
4073
4074#ifndef NDEBUG
4075 {
4076 /* in debug mode we check that we adjust the search position correctly */
4077 int tmppos;
4078
4079 (void)SCIPprofileFindLeft(profile, est, &tmppos);
4080 assert(pos == tmppos);
4081 }
4082#endif
4083 ect = est + duration;
4084 peak = -1;
4085
4086 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4087 * want a peak which is closest to the earliest completion time
4088 */
4089 do
4090 {
4091 /* check if the profile load conflicts with the demand of the start time variable */
4092 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4093 peak = pos;
4094
4095 pos++;
4096 }
4097 while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4098
4099 /* if we found no peak that means current the job could be scheduled at its earliest start time without
4100 * conflicting to the core resource profile
4101 */
4102 /* coverity[check_after_sink] */
4103 if( peak == -1 )
4104 break;
4105
4106 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4107 * profile. That means we have to move it to the next time point in the resource profile but at most to the
4108 * earliest completion time (the remaining move will done in the next loop)
4109 */
4110 newlb = SCIPprofileGetTime(profile, peak+1);
4111 newlb = MIN(newlb, ect);
4112
4113 /* if the earliest start time is greater than the lst we detected an infeasibilty */
4114 if( newlb > lst )
4115 {
4116 SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4117
4118 /* use conflict analysis to analysis the core insertion which was infeasible */
4119 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4120 var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4121
4122 if( explanation != NULL )
4123 explanation[idx] = TRUE;
4124
4125 *infeasible = TRUE;
4126
4127 break;
4128 }
4129
4130 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4131 * bound change
4132 */
4133 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4134
4135 /* perform the bound lower bound change */
4136 if( inferInfoIsValid(inferinfo) )
4137 {
4138 SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4139 }
4140 else
4141 {
4142 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4143 }
4144 assert(tightened);
4145 assert(!(*infeasible));
4146
4147 SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4148 (*nchgbds)++;
4149
4150 /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4152
4153 /* adjust the earliest start time
4154 *
4155 * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4156 * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4157 * involved.
4158 */
4160 assert(est >= newlb);
4161
4162 /* adjust the search position for the resource profile for the next step */
4163 if( est == SCIPprofileGetTime(profile, peak+1) )
4164 pos = peak + 1;
4165 else
4166 pos = peak;
4167 }
4168 while( est < lst );
4169
4170 return SCIP_OKAY;
4171}
4172
4173/** We are using the core resource profile which contains all core except the one of the start time variable which we
4174 * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4175 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4176 * analysis
4177 */
4178static
4180 SCIP* scip, /**< SCIP data structure */
4181 SCIP_VAR* var, /**< start time variable to propagate */
4182 int duration, /**< duration of the job */
4183 int demand, /**< demand of the job */
4184 int capacity, /**< cumulative capacity */
4185 SCIP_CONS* cons, /**< constraint which is propagated */
4186 SCIP_PROFILE* profile, /**< resource profile */
4187 int idx, /**< position of the variable to propagate */
4188 int* nchgbds /**< pointer to store the number of bound changes */
4189 )
4190{
4191 int ntimepoints;
4192 int newub;
4193 int peak;
4194 int pos;
4195 int est;
4196 int lst;
4197 int lct;
4198
4199 assert(var != NULL);
4200 assert(duration > 0);
4201 assert(demand > 0);
4202
4205
4206 /* in case the start time variable is fixed do nothing */
4207 if( est == lst )
4208 return SCIP_OKAY;
4209
4210 ntimepoints = SCIPprofileGetNTimepoints(profile);
4211
4212 lct = lst + duration;
4213
4214 /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4215 * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4216 * position gives us the load which we have at the latest completion time minus one
4217 */
4218 (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4219
4220 SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4222
4223 if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4224 return SCIP_OKAY;
4225
4226 /* we now trying to move the latest start time in steps of at most "duration" length */
4227 do
4228 {
4229 INFERINFO inferinfo;
4230 SCIP_Bool tightened;
4231 SCIP_Bool infeasible;
4232
4233 peak = -1;
4234
4235#ifndef NDEBUG
4236 {
4237 /* in debug mode we check that we adjust the search position correctly */
4238 int tmppos;
4239
4240 (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4241 assert(pos == tmppos);
4242 }
4243#endif
4244
4245 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4246 * want a peak which is closest to the latest start time
4247 */
4248 do
4249 {
4250 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4251 peak = pos;
4252
4253 pos--;
4254 }
4255 while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4256
4257 /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4258 * to the core resource profile
4259 */
4260 /* coverity[check_after_sink] */
4261 if( peak == -1 )
4262 break;
4263
4264 /* the peak position gives us a time point where the start time variable is in conflict with the resource
4265 * profile. That means the job has be done until that point. Hence that gives us the latest completion
4266 * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4267 * doing in the next loop)
4268 */
4269 newub = SCIPprofileGetTime(profile, peak);
4270 newub = MAX(newub, lst) - duration;
4271 assert(newub >= est);
4272
4273 /* construct the inference information which we are using with the conflict analysis to resolve that particular
4274 * bound change
4275 */
4276 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4277
4278 /* perform the bound upper bound change */
4279 if( inferInfoIsValid(inferinfo) )
4280 {
4281 SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4282 }
4283 else
4284 {
4285 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4286 }
4287 assert(tightened);
4288 assert(!infeasible);
4289
4290 SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4291 (*nchgbds)++;
4292
4293 /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4295
4296 /* adjust the latest start and completion time
4297 *
4298 * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4299 * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4300 * involved.
4301 */
4303 assert(lst <= newub);
4304 lct = lst + duration;
4305
4306 /* adjust the search position for the resource profile for the next step */
4307 if( SCIPprofileGetTime(profile, peak) == lct )
4308 pos = peak - 1;
4309 else
4310 pos = peak;
4311 }
4312 while( est < lst );
4313
4314 return SCIP_OKAY;
4315}
4316
4317/** compute for the different earliest start and latest completion time the core energy of the corresponding time
4318 * points
4319 */
4320static
4322 SCIP_PROFILE* profile, /**< core profile */
4323 int nvars, /**< number of start time variables (activities) */
4324 int* ests, /**< array of sorted earliest start times */
4325 int* lcts, /**< array of sorted latest completion times */
4326 int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4327 int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4328 )
4329{
4330 int ntimepoints;
4331 int energy;
4332 int t;
4333 int v;
4334
4335 ntimepoints = SCIPprofileGetNTimepoints(profile);
4336 t = ntimepoints - 1;
4337 energy = 0;
4338
4339 /* compute core energy after the earliest start time of each job */
4340 for( v = nvars-1; v >= 0; --v )
4341 {
4342 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4343 {
4344 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4345 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4346 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4347 t--;
4348 }
4349 assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4350
4351 /* maybe ests[j] is in-between two timepoints */
4352 if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4353 {
4354 assert(t > 0);
4355 coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4356 }
4357 else
4359 }
4360
4361 t = ntimepoints - 1;
4362 energy = 0;
4363
4364 /* compute core energy after the latest completion time of each job */
4365 for( v = nvars-1; v >= 0; --v )
4366 {
4367 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4368 {
4369 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4370 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4371 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4372 t--;
4373 }
4374 assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4375
4376 /* maybe lcts[j] is in-between two timepoints */
4377 if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4378 {
4379 assert(t > 0);
4380 coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4381 }
4382 else
4384 }
4385}
4386
4387/** collect earliest start times, latest completion time, and free energy contributions */
4388static
4390 SCIP* scip, /**< SCIP data structure */
4391 int nvars, /**< number of start time variables (activities) */
4392 SCIP_VAR** vars, /**< array of start time variables */
4393 int* durations, /**< array of durations */
4394 int* demands, /**< array of demands */
4395 int hmin, /**< left bound of time axis to be considered (including hmin) */
4396 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4397 int* permests, /**< array to store the variable positions */
4398 int* ests, /**< array to store earliest start times */
4399 int* permlcts, /**< array to store the variable positions */
4400 int* lcts, /**< array to store latest completion times */
4401 int* ects, /**< array to store earliest completion times of the flexible part of the job */
4402 int* lsts, /**< array to store latest start times of the flexible part of the job */
4403 int* flexenergies /**< array to store the flexible energies of each job */
4404 )
4405{
4406 int v;
4407
4408 for( v = 0; v < nvars; ++ v)
4409 {
4410 int duration;
4411 int leftadjust;
4412 int rightadjust;
4413 int core;
4414 int est;
4415 int lct;
4416 int ect;
4417 int lst;
4418
4419 duration = durations[v];
4420 assert(duration > 0);
4421
4424 ect = est + duration;
4425 lct = lst + duration;
4426
4427 ests[v] = est;
4428 lcts[v] = lct;
4429 permests[v] = v;
4430 permlcts[v] = v;
4431
4432 /* compute core time window which lies within the effective horizon */
4433 core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4434
4435 /* compute the number of time steps the job could run before the effective horizon */
4436 leftadjust = MAX(0, hmin - est);
4437
4438 /* compute the number of time steps the job could run after the effective horizon */
4439 rightadjust = MAX(0, lct - hmax);
4440
4441 /* compute for each job the energy which is flexible; meaning not part of the core */
4442 flexenergies[v] = duration - leftadjust - rightadjust - core;
4443 flexenergies[v] = MAX(0, flexenergies[v]);
4444 flexenergies[v] *= demands[v];
4445 assert(flexenergies[v] >= 0);
4446
4447 /* the earliest completion time of the flexible energy */
4448 ects[v] = MIN(ect, lst);
4449
4450 /* the latest start time of the flexible energy */
4451 lsts[v] = MAX(ect, lst);
4452 }
4453}
4454
4455/** try to tighten the lower bound of the given variable */
4456static
4458 SCIP* scip, /**< SCIP data structure */
4459 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4460 int nvars, /**< number of start time variables (activities) */
4461 SCIP_VAR** vars, /**< array of start time variables */
4462 int* durations, /**< array of durations */
4463 int* demands, /**< array of demands */
4464 int capacity, /**< cumulative capacity */
4465 int hmin, /**< left bound of time axis to be considered (including hmin) */
4466 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4467 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4468 int duration, /**< duration of the job */
4469 int demand, /**< demand of the job */
4470 int est, /**< earliest start time of the job */
4471 int ect, /**< earliest completion time of the flexible part of the job */
4472 int lct, /**< latest completion time of the job */
4473 int begin, /**< begin of the time window under investigation */
4474 int end, /**< end of the time window under investigation */
4475 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4476 int* bestlb, /**< pointer to strope the best lower bound change */
4477 int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4478 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4479 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4480 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4481 )
4482{
4483 int newlb;
4484
4485 assert(begin >= hmin);
4486 assert(end <= hmax);
4487
4488 /* check if the time-table edge-finding should infer bounds */
4489 if( !conshdlrdata->ttefinfer )
4490 return SCIP_OKAY;
4491
4492 /* if the job can be processed completely before or after the time window, nothing can be tightened */
4493 if( est >= end || ect <= begin )
4494 return SCIP_OKAY;
4495
4496 /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4497 * skip since the overload check will do the job
4498 */
4499 if( est >= begin && ect <= end )
4500 return SCIP_OKAY;
4501
4502 /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4503 * earliest start time
4504 */
4505 if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4506 return SCIP_OKAY;
4507
4508 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4509 * present; therefore, we need to add the core;
4510 *
4511 * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4512 * compute the earliest completion time of the (whole) job
4513 */
4514 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4515
4516 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4517 *
4518 * @note we can round down the compute duration w.r.t. the available energy
4519 */
4520 newlb = end - (int) (energy / demand);
4521
4522 /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4523 * bound (latest start time); meaning it is not possible to schedule the job
4524 */
4525 if( newlb > lct - duration )
4526 {
4527 /* initialize conflict analysis if conflict analysis is applicable */
4529 {
4530 SCIP_Real relaxedbd;
4531
4533
4534 /* it is enough to overshoot the upper bound of the variable by one */
4536
4537 /* initialize conflict analysis */
4539
4540 /* added to upper bound (which was overcut be new lower bound) of the variable */
4542
4543 /* analyze the infeasible */
4544 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4545 begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4546
4547 (*initialized) = TRUE;
4548 }
4549
4550 (*cutoff) = TRUE;
4551 }
4552 else if( newlb > (*bestlb) )
4553 {
4554 INFERINFO inferinfo;
4555
4556 assert(newlb > begin);
4557
4558 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4559
4560 /* construct inference information */
4561 (*inferinfos) = inferInfoToInt(inferinfo);
4562 (*bestlb) = newlb;
4563 }
4564
4565 return SCIP_OKAY;
4566}
4567
4568/** try to tighten the upper bound of the given variable */
4569static
4571 SCIP* scip, /**< SCIP data structure */
4572 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4573 int nvars, /**< number of start time variables (activities) */
4574 SCIP_VAR** vars, /**< array of start time variables */
4575 int* durations, /**< array of durations */
4576 int* demands, /**< array of demands */
4577 int capacity, /**< cumulative capacity */
4578 int hmin, /**< left bound of time axis to be considered (including hmin) */
4579 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4580 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4581 int duration, /**< duration of the job */
4582 int demand, /**< demand of the job */
4583 int est, /**< earliest start time of the job */
4584 int lst, /**< latest start time of the flexible part of the job */
4585 int lct, /**< latest completion time of the job */
4586 int begin, /**< begin of the time window under investigation */
4587 int end, /**< end of the time window under investigation */
4588 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4589 int* bestub, /**< pointer to strope the best upper bound change */
4590 int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4591 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4592 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4593 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4594 )
4595{
4596 int newub;
4597
4598 assert(begin >= hmin);
4599 assert(end <= hmax);
4600 assert(est < begin);
4601
4602 /* check if the time-table edge-finding should infer bounds */
4603 if( !conshdlrdata->ttefinfer )
4604 return SCIP_OKAY;
4605
4606 /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4607 if( lst >= end || lct <= begin )
4608 return SCIP_OKAY;
4609
4610 /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4611 * skip since the overload check will do the job
4612 */
4613 if( lst >= begin && lct <= end )
4614 return SCIP_OKAY;
4615
4616 /* check if the available energy in the time window is to small to handle the flexible part of the job */
4617 if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4618 return SCIP_OKAY;
4619
4620 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4621 * present; therefore, we need to add the core;
4622 *
4623 * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4624 * latest start of the (whole) job
4625 */
4626 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4627 assert(energy >= 0);
4628
4629 /* compute a latest start time (upper bound) such that the job consums at most the available energy
4630 *
4631 * @note we can round down the compute duration w.r.t. the available energy
4632 */
4633 assert(demand > 0);
4634 newub = begin - duration + (int) (energy / demand);
4635
4636 /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4637 * bound (earliest start time); meaning it is not possible to schedule the job
4638 */
4639 if( newub < est )
4640 {
4641 /* initialize conflict analysis if conflict analysis is applicable */
4643 {
4644 SCIP_Real relaxedbd;
4645
4647
4648 /* it is enough to undershoot the lower bound of the variable by one */
4650
4651 /* initialize conflict analysis */
4653
4654 /* added to lower bound (which was undercut be new upper bound) of the variable */
4656
4657 /* analyze the infeasible */
4658 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4659 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4660
4661 (*initialized) = TRUE;
4662 }
4663
4664 (*cutoff) = TRUE;
4665 }
4666 else if( newub < (*bestub) )
4667 {
4668 INFERINFO inferinfo;
4669
4670 assert(newub < begin);
4671
4672 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4673
4674 /* construct inference information */
4675 (*inferinfos) = inferInfoToInt(inferinfo);
4676 (*bestub) = newub;
4677 }
4678
4679 return SCIP_OKAY;
4680}
4681
4682/** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4683static
4685 SCIP* scip, /**< SCIP data structure */
4686 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4687 int nvars, /**< number of start time variables (activities) */
4688 SCIP_VAR** vars, /**< array of start time variables */
4689 int* durations, /**< array of durations */
4690 int* demands, /**< array of demands */
4691 int capacity, /**< cumulative capacity */
4692 int hmin, /**< left bound of time axis to be considered (including hmin) */
4693 int hmax, /**< right bound of time axis to be considered (not including hmax) */
4694 int* newlbs, /**< array to buffer new lower bounds */
4695 int* newubs, /**< array to buffer new upper bounds */
4696 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4697 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4698 int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4699 int* flexenergies, /**< array of flexible energies in the same order as the variables */
4700 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4701 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4702 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4703 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4704 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4705 SCIP_Bool* initialized, /**< was conflict analysis initialized */
4706 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4707 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4708 )
4709{
4711 SCIP_Longint maxavailable;
4712 SCIP_Longint minavailable;
4713 SCIP_Longint totalenergy;
4714 int nests;
4715 int est;
4716 int lct;
4717 int start;
4718 int end;
4719 int v;
4720
4721 est = INT_MAX;
4722 lct = INT_MIN;
4723
4724 /* compute earliest start and latest completion time of all jobs */
4725 for( v = 0; v < nvars; ++v )
4726 {
4728 end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4729
4730 est = MIN(est, start);
4731 lct = MAX(lct, end);
4732 }
4733
4734 /* adjust the effective time horizon */
4735 hmin = MAX(hmin, est);
4736 hmax = MIN(hmax, lct);
4737
4738 end = hmax + 1;
4739 coreEnergyAfterEnd = -1;
4740
4741 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4743 totalenergy = computeTotalEnergy(durations, demands, nvars);
4744
4745 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4746 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4747 return SCIP_OKAY;
4748
4749 nests = nvars;
4750
4751 /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4752 * times define the end of the time interval under investigation
4753 */
4754 for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4755 {
4756 int flexenergy;
4757 int minbegin;
4758 int lbenergy;
4759 int lbcand;
4760 int i;
4761
4762 lct = lcts[v];
4763
4764 /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4765 * infinity capacity is available; hence we skip that
4766 */
4767 if( lct > hmax )
4768 continue;
4769
4770 /* if the latest completion time is smaller then hmin we have to stop */
4771 if( lct <= hmin )
4772 {
4773 assert(v == 0 || lcts[v-1] <= lcts[v]);
4774 break;
4775 }
4776
4777 /* if the latest completion time equals to previous end time, we can continue since this particular interval
4778 * induced by end was just analyzed
4779 */
4780 if( lct == end )
4781 continue;
4782
4783 assert(lct < end);
4784
4785 /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4786 * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4787 * free energy; if so it means that in the next iterate the free-energy cannot be negative
4788 */
4789 if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4790 {
4791 SCIP_Longint freeenergy;
4792
4795
4796 /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4797 freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4798
4799 if( freeenergy <= minavailable )
4800 {
4801 SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4802 continue;
4803 }
4804 }
4805
4806 SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4807
4808 end = lct;
4810
4811 flexenergy = 0;
4813 minbegin = hmax;
4814 lbcand = -1;
4815 lbenergy = 0;
4816
4817 /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4818 * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4819 * wider
4820 */
4821 for( i = nests-1; i >= 0; --i )
4822 {
4823 SCIP_VAR* var;
4824 SCIP_Longint freeenergy;
4825 int duration;
4826 int demand;
4827 int begin;
4828 int idx;
4829 int lst;
4830
4831 idx = perm[i];
4832 assert(idx >= 0);
4833 assert(idx < nvars);
4834 assert(!(*cutoff));
4835
4836 /* the earliest start time of the job */
4837 est = ests[i];
4838
4839 /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4840 * latest completion times (which define end) are scant in non-increasing order
4841 */
4842 if( end <= est )
4843 {
4844 nests--;
4845 continue;
4846 }
4847
4848 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4849 * current ending time
4850 */
4851 if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4852 break;
4853
4854 var = vars[idx];
4855 assert(var != NULL);
4856
4857 duration = durations[idx];
4858 assert(duration > 0);
4859
4860 demand = demands[idx];
4861 assert(demand > 0);
4862
4863 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4864
4865 /* the latest start time of the free part of the job */
4866 lst = lsts[idx];
4867
4868 /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4869 * investigation; hence the overload check will do the the job
4870 */
4871 assert(est <= minbegin);
4872 if( minavailable < maxavailable && est < minbegin )
4873 {
4874 assert(!(*cutoff));
4875
4876 /* try to tighten the upper bound */
4877 SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4878 var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4879 initialized, explanation, cutoff) );
4880
4881 if( *cutoff )
4882 break;
4883 }
4884
4885 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4886 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4887
4888 begin = est;
4890
4891 /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4892 * free energy
4893 */
4894 if( begin < hmin )
4895 break;
4896
4897 /* compute the contribution to the flexible energy */
4898 if( lct <= end )
4899 {
4900 /* if the jobs has to finish before the end, all the energy has to be scheduled */
4901 assert(lst >= begin);
4902 assert(flexenergies[idx] >= 0);
4903 flexenergy += flexenergies[idx];
4904 }
4905 else
4906 {
4907 /* the job partly overlaps with the end */
4908 int candenergy;
4909 int energy;
4910
4911 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4912 * w.r.t. latest start time
4913 *
4914 * @note we need to be aware of the effective horizon
4915 */
4916 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4917 assert(end - lst < duration);
4918 assert(energy >= 0);
4919
4920 /* adjust the flexible energy of the time interval */
4921 flexenergy += energy;
4922
4923 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4924 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4925 assert(candenergy >= 0);
4926
4927 /* check if we found a better candidate */
4928 if( candenergy > lbenergy )
4929 {
4931 lbcand = idx;
4932 }
4933 }
4934
4935 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4937
4938 /* compute the energy which is not used yet */
4940
4941 /* check overload */
4942 if( freeenergy < 0 )
4943 {
4944 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4945
4946 /* initialize conflict analysis if conflict analysis is applicable */
4948 {
4949 /* analyze infeasibilty */
4951
4952 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4954 conshdlrdata->usebdwidening, explanation) );
4955
4956 (*initialized) = TRUE;
4957 }
4958
4959 (*cutoff) = TRUE;
4960
4961 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4963
4964 break;
4965 }
4966
4967 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4968 if( lbenergy > 0 && freeenergy < lbenergy )
4969 {
4970 SCIP_Longint energy;
4971 int newlb;
4972 int ect;
4973
4976
4977 /* remove the energy of our job from the ... */
4978 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4979
4980 newlb = end - (int)(energy / demands[lbcand]);
4981
4982 if( newlb > lst )
4983 {
4984 /* initialize conflict analysis if conflict analysis is applicable */
4986 {
4987 SCIP_Real relaxedbd;
4988
4989 /* analyze infeasibilty */
4991
4992 relaxedbd = lst + 1.0;
4993
4994 /* added to upper bound (which was overcut be new lower bound) of the variable */
4996
4997 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4999 conshdlrdata->usebdwidening, explanation) );
5000
5001 (*initialized) = TRUE;
5002 }
5003
5004 (*cutoff) = TRUE;
5005 break;
5006 }
5007 else if( newlb > newlbs[lbcand] )
5008 {
5009 INFERINFO inferinfo;
5010
5011 /* construct inference information */
5012 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5013
5014 /* buffer upper bound change */
5015 lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
5016 newlbs[lbcand] = newlb;
5017 }
5018 }
5019
5020 /* check if the current interval has a smaller free energy */
5021 if( minavailable > freeenergy )
5022 {
5024 minbegin = begin;
5025 }
5026 assert(minavailable >= 0);
5027 }
5028 }
5029
5030 return SCIP_OKAY;
5031}
5032
5033/** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
5034static
5036 SCIP* scip, /**< SCIP data structure */
5037 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5038 int nvars, /**< number of start time variables (activities) */
5039 SCIP_VAR** vars, /**< array of start time variables */
5040 int* durations, /**< array of durations */
5041 int* demands, /**< array of demands */
5042 int capacity, /**< cumulative capacity */
5043 int hmin, /**< left bound of time axis to be considered (including hmin) */
5044 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5045 int* newlbs, /**< array to buffer new lower bounds */
5046 int* newubs, /**< array to buffer new upper bounds */
5047 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5048 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5049 int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5050 int* flexenergies, /**< array of flexible energies in the same order as the variables */
5051 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5052 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5053 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5054 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5055 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5056 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5057 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5058 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5059 )
5060{
5062 SCIP_Longint maxavailable;
5063 SCIP_Longint minavailable;
5064 SCIP_Longint totalenergy;
5065 int nlcts;
5066 int begin;
5067 int minest;
5068 int maxlct;
5069 int start;
5070 int end;
5071 int v;
5072
5073 if( *cutoff )
5074 return SCIP_OKAY;
5075
5076 begin = hmin - 1;
5077
5078 minest = INT_MAX;
5079 maxlct = INT_MIN;
5080
5081 /* compute earliest start and latest completion time of all jobs */
5082 for( v = 0; v < nvars; ++v )
5083 {
5085 end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5086
5087 minest = MIN(minest, start);
5088 maxlct = MAX(maxlct, end);
5089 }
5090
5091 /* adjust the effective time horizon */
5092 hmin = MAX(hmin, minest);
5093 hmax = MIN(hmax, maxlct);
5094
5095 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5096 totalenergy = computeTotalEnergy(durations, demands, nvars);
5097
5098 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5099 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5100 return SCIP_OKAY;
5101
5102 nlcts = 0;
5103
5104 /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5105 * define the start of the time interval under investigation
5106 */
5107 for( v = 0; v < nvars; ++v )
5108 {
5109 int flexenergy;
5110 int minend;
5111 int ubenergy;
5112 int ubcand;
5113 int est;
5114 int i;
5115
5116 est = ests[v];
5117
5118 /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5119 * infinity capacity is available; hence we skip that
5120 */
5121 if( est < hmin )
5122 continue;
5123
5124 /* if the earliest start time is larger or equal then hmax we have to stop */
5125 if( est >= hmax )
5126 break;
5127
5128 /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5129 * induced by start was just analyzed
5130 */
5131 if( est == begin )
5132 continue;
5133
5134 assert(est > begin);
5135
5136 SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5137
5138 begin = est;
5140
5141 flexenergy = 0;
5143 minend = hmin;
5144 ubcand = -1;
5145 ubenergy = 0;
5146
5147 /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5148 * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5149 */
5150 for( i = nlcts; i < nvars; ++i )
5151 {
5152 SCIP_VAR* var;
5153 SCIP_Longint freeenergy;
5154 int duration;
5155 int demand;
5156 int idx;
5157 int lct;
5158 int ect;
5159
5160 idx = perm[i];
5161 assert(idx >= 0);
5162 assert(idx < nvars);
5163 assert(!(*cutoff));
5164
5165 /* the earliest start time of the job */
5166 lct = lcts[i];
5167
5168 /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5169 * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5170 */
5171 if( lct <= begin )
5172 {
5173 nlcts++;
5174 continue;
5175 }
5176
5177 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5178 * start with current beginning time
5179 */
5180 if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5181 break;
5182
5183 var = vars[idx];
5184 assert(var != NULL);
5185
5186 duration = durations[idx];
5187 assert(duration > 0);
5188
5189 demand = demands[idx];
5190 assert(demand > 0);
5191
5193
5194 /* the earliest completion time of the flexible part of the job */
5195 ect = ects[idx];
5196
5197 /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5198 * investigation; hence the overload check will do the the job
5199 */
5200 assert(lct >= minend);
5202 {
5203 assert(!(*cutoff));
5204
5205 /* try to tighten the upper bound */
5206 SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5207 var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5208 initialized, explanation, cutoff) );
5209
5210 if( *cutoff )
5211 return SCIP_OKAY;
5212 }
5213
5214 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5215 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5216
5217 end = lct;
5219
5220 /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5221 * free energy
5222 */
5223 if( end > hmax )
5224 break;
5225
5226 /* compute the contribution to the flexible energy */
5227 if( est >= begin )
5228 {
5229 /* if the jobs has to finish before the end, all the energy has to be scheduled */
5230 assert(ect <= end);
5231 assert(flexenergies[idx] >= 0);
5232 flexenergy += flexenergies[idx];
5233 }
5234 else
5235 {
5236 /* the job partly overlaps with the end */
5237 int candenergy;
5238 int energy;
5239
5240 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5241 * w.r.t. latest start time
5242 *
5243 * @note we need to be aware of the effective horizon
5244 */
5245 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5246 assert(ect - begin < duration);
5247 assert(energy >= 0);
5248
5249 /* adjust the flexible energy of the time interval */
5250 flexenergy += energy;
5251
5252 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5253 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5254 assert(candenergy >= 0);
5255
5256 /* check if we found a better candidate */
5257 if( candenergy > ubenergy )
5258 {
5260 ubcand = idx;
5261 }
5262 }
5263
5264 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5266
5267 /* compute the energy which is not used yet */
5269
5270 /* check overload */
5271 if( freeenergy < 0 )
5272 {
5273 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5274
5275 /* initialize conflict analysis if conflict analysis is applicable */
5277 {
5278 /* analyze infeasibilty */
5280
5281 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5283 conshdlrdata->usebdwidening, explanation) );
5284
5285 (*initialized) = TRUE;
5286 }
5287
5288 (*cutoff) = TRUE;
5289
5290 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5292
5293 return SCIP_OKAY;
5294 }
5295
5296 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5297 if( ubenergy > 0 && freeenergy < ubenergy )
5298 {
5299 SCIP_Longint energy;
5300 int newub;
5301 int lst;
5302
5303 duration = durations[ubcand];
5304 assert(duration > 0);
5305
5308
5309 /* remove the energy of our job from the ... */
5310 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5311
5312 newub = begin - duration + (int)(energy / demands[ubcand]);
5313
5314 if( newub < ect - duration )
5315 {
5316 /* initialize conflict analysis if conflict analysis is applicable */
5318 {
5319 SCIP_Real relaxedbd;
5320 /* analyze infeasibilty */
5322
5323 relaxedbd = ect - duration - 1.0;
5324
5325 /* added to lower bound (which was undercut be new upper bound) of the variable */
5327
5328 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5330 conshdlrdata->usebdwidening, explanation) );
5331
5332 (*initialized) = TRUE;
5333 }
5334
5335 (*cutoff) = TRUE;
5336 return SCIP_OKAY;
5337 }
5338 else if( newub < newubs[ubcand] )
5339 {
5340 INFERINFO inferinfo;
5341
5342 /* construct inference information */
5343 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5344
5345 /* buffer upper bound change */
5346 ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5347 newubs[ubcand] = newub;
5348 }
5349 }
5350
5351 /* check if the current interval has a smaller free energy */
5352 if( minavailable > freeenergy )
5353 {
5355 minend = end;
5356 }
5357 assert(minavailable >= 0);
5358 }
5359 }
5360
5361 return SCIP_OKAY;
5362}
5363
5364/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5365 * edge-finding
5366 *
5367 * @note The algorithm is based on the following two papers:
5368 * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5369 * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5370 * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5371 * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5372 * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5373 */
5374static
5376 SCIP* scip, /**< SCIP data structure */
5377 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5378 SCIP_PROFILE* profile, /**< current core profile */
5379 int nvars, /**< number of start time variables (activities) */
5380 SCIP_VAR** vars, /**< array of start time variables */
5381 int* durations, /**< array of durations */
5382 int* demands, /**< array of demands */
5383 int capacity, /**< cumulative capacity */
5384 int hmin, /**< left bound of time axis to be considered (including hmin) */
5385 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5386 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5387 int* nchgbds, /**< pointer to store the number of bound changes */
5388 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5389 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5390 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5391 )
5392{
5393 int* coreEnergyAfterEst;
5394 int* coreEnergyAfterLct;
5395 int* flexenergies;
5396 int* permests;
5397 int* permlcts;
5398 int* lcts;
5399 int* ests;
5400 int* ects;
5401 int* lsts;
5402
5403 int* newlbs;
5404 int* newubs;
5405 int* lbinferinfos;
5406 int* ubinferinfos;
5407
5408 int v;
5409
5410 /* check if a cutoff was already detected */
5411 if( (*cutoff) )
5412 return SCIP_OKAY;
5413
5414 /* check if at least the basic overload checking should be perfomed */
5415 if( !conshdlrdata->ttefcheck )
5416 return SCIP_OKAY;
5417
5418 SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5419
5429
5434
5435 /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5436 for( v = 0; v < nvars; ++v )
5437 {
5440 lbinferinfos[v] = 0;
5441 ubinferinfos[v] = 0;
5442 }
5443
5444 /* collect earliest start times, latest completion time, and free energy contributions */
5445 collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5446
5447 /* sort the earliest start times and latest completion in non-decreasing order */
5450
5451 /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5452 * points
5453 */
5455
5456 /* propagate the upper bounds and "opportunistically" the lower bounds */
5457 SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5460
5461 /* propagate the lower bounds and "opportunistically" the upper bounds */
5462 SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5465
5466 /* apply the buffer bound changes */
5467 for( v = 0; v < nvars && !(*cutoff); ++v )
5468 {
5469 SCIP_Bool infeasible;
5470 SCIP_Bool tightened;
5471
5473 {
5474 SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5475 TRUE, &infeasible, &tightened) );
5476 }
5477 else
5478 {
5479 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5480 }
5481
5482 /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5483 assert(!infeasible);
5484
5485 if( tightened )
5486 {
5487 (*nchgbds)++;
5488
5489 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5491 }
5492
5494 {
5495 SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5496 TRUE, &infeasible, &tightened) );
5497 }
5498 else
5499 {
5500 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5501 }
5502
5503 /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5504 * bound update can be infeasible
5505 */
5506 if( infeasible )
5507 {
5508 /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5509 * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5510 * be analyzed in the case when begin and end exceed the 15 bit limit
5511 */
5513 {
5514 INFERINFO inferinfo;
5515 SCIP_VAR* var;
5516 int begin;
5517 int end;
5518
5519 var = vars[v];
5520 assert(var != NULL);
5521
5522 /* initialize conflict analysis */
5524
5525 /* convert int to inference information */
5526 inferinfo = intToInferInfo(ubinferinfos[v]);
5527
5528 /* collect time window from inference information */
5529 begin = inferInfoGetData1(inferinfo);
5530 end = inferInfoGetData2(inferinfo);
5531 assert(begin < end);
5532
5533 /* added to lower bound (which was undercut be new upper bound) of the variable */
5535
5536 /* analysis the upper bound change */
5537 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5539 conshdlrdata->usebdwidening, explanation) );
5540
5541 (*initialized) = TRUE;
5542 }
5543
5544 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5546
5547 (*cutoff) = TRUE;
5548 break;
5549 }
5550
5551 if( tightened )
5552 {
5553 (*nchgbds)++;
5554
5555 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5557 }
5558 }
5559
5564
5565 /* free buffer arrays */
5575
5576 return SCIP_OKAY;
5577}
5578
5579/** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5580 * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5581 * time table propagator
5582 */
5583static
5585 SCIP* scip, /**< SCIP data structure */
5586 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5587 SCIP_PROFILE* profile, /**< core profile */
5588 int nvars, /**< number of start time variables (activities) */
5589 SCIP_VAR** vars, /**< array of start time variables */
5590 int* durations, /**< array of durations */
5591 int* demands, /**< array of demands */
5592 int capacity, /**< cumulative capacity */
5593 int hmin, /**< left bound of time axis to be considered (including hmin) */
5594 int hmax, /**< right bound of time axis to be considered (not including hmax) */
5595 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5596 int* nchgbds, /**< pointer to store the number of bound changes */
5597 SCIP_Bool* initialized, /**< was conflict analysis initialized */
5598 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5599 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5600 )
5601{
5602 SCIP_Bool infeasible;
5603 int v;
5604
5605 assert(scip != NULL);
5606 assert(nvars > 0);
5607 assert(cons != NULL);
5608 assert(cutoff != NULL);
5609
5610 /* check if already a cutoff was detected */
5611 if( (*cutoff) )
5612 return SCIP_OKAY;
5613
5614 /* check if the time tabling should infer bounds */
5615 if( !conshdlrdata->ttinfer )
5616 return SCIP_OKAY;
5617
5618 assert(*initialized == FALSE);
5619
5620 SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5621 SCIPconsGetName(cons), hmin, hmax, capacity);
5622
5623 infeasible = FALSE;
5624
5625 /* if core profile is empty; nothing to do */
5626 if( SCIPprofileGetNTimepoints(profile) <= 1 )
5627 return SCIP_OKAY;
5628
5629 /* start checking each job whether the bounds can be improved */
5630 for( v = 0; v < nvars; ++v )
5631 {
5632 SCIP_VAR* var;
5633 int demand;
5634 int duration;
5635 int begin;
5636 int end;
5637 int est;
5638 int lst;
5639
5640 var = vars[v];
5641 assert(var != NULL);
5642
5643 duration = durations[v];
5644 assert(duration > 0);
5645
5646 /* collect earliest and latest start time */
5649
5650 /* check if the start time variables is already fixed; in that case we can ignore the job */
5651 if( est == lst )
5652 continue;
5653
5654 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5655 if( lst + duration <= hmin || est >= hmax )
5656 continue;
5657
5658 /* compute core interval w.r.t. effective time horizon */
5659 begin = MAX(hmin, lst);
5660 end = MIN(hmax, est + duration);
5661
5662 demand = demands[v];
5663 assert(demand > 0);
5664
5665 /* if the job has a core, remove it first */
5666 if( begin < end )
5667 {
5668 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5670
5671 SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5672 }
5673
5674 /* first try to update the earliest start time */
5675 SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5676 profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5677
5678 if( *cutoff )
5679 break;
5680
5681 /* second try to update the latest start time */
5682 SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5683 profile, v, nchgbds) );
5684
5685 if( *cutoff )
5686 break;
5687
5688 /* collect the potentially updated earliest and latest start time */
5691
5692 /* compute core interval w.r.t. effective time horizon */
5693 begin = MAX(hmin, lst);
5694 end = MIN(hmax, est + duration);
5695
5696 /* after updating the bound we might have a new core */
5697 if( begin < end )
5698 {
5699 int pos;
5700
5701 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5702 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5703
5704 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5705
5706 if( infeasible )
5707 {
5708 /* use conflict analysis to analysis the core insertion which was infeasible */
5709 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5710 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5711
5712 if( explanation != NULL )
5713 explanation[v] = TRUE;
5714
5715 (*cutoff) = TRUE;
5716
5717 /* for the statistic we count the number of times a cutoff was detected due the time-time */
5719
5720 break;
5721 }
5722 }
5723 }
5724
5725 return SCIP_OKAY;
5726}
5727
5728
5729/** node data structure for the binary tree used for edgefinding (with overload checking) */
5730struct SCIP_NodeData
5731{
5732 SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5733 SCIP_Real key; /**< key which is to insert the corresponding search node */
5734 int est; /**< earliest start time if the node data belongs to a leaf */
5735 int lct; /**< latest completion time if the node data belongs to a leaf */
5736 int demand; /**< demand of the job if the node data belongs to a leaf */
5737 int duration; /**< duration of the job if the node data belongs to a leaf */
5738 int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5739 int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5740 SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5741 int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5742 int energylambda;
5743 SCIP_Longint enveloplambda;
5744 int idx; /**< index of the start time variable in the (global) variable array */
5745 SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5746};
5747typedef struct SCIP_NodeData SCIP_NODEDATA;
5748
5749
5750/** update node data structure starting from the given node along the path to the root node */
5751static
5753 SCIP* scip, /**< SCIP data structure */
5754 SCIP_BTNODE* node /**< search node which inserted */
5755 )
5756{
5757 SCIP_BTNODE* left;
5758 SCIP_BTNODE* right;
5762
5763 SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5764
5765 if( SCIPbtnodeIsLeaf(node) )
5766 node = SCIPbtnodeGetParent(node);
5767
5768 while( node != NULL )
5769 {
5770 /* get node data */
5772 assert(nodedata != NULL);
5773
5774 /* collect node data from left node */
5775 left = SCIPbtnodeGetLeftchild(node);
5776 assert(left != NULL);
5778 assert(leftdata != NULL);
5779
5780 /* collect node data from right node */
5781 right = SCIPbtnodeGetRightchild(node);
5782 assert(right != NULL);
5784 assert(rightdata != NULL);
5785
5786 /* update envelop and energy */
5787 if( leftdata->enveloptheta >= 0 )
5788 {
5789 assert(rightdata->energytheta != -1);
5790 nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5791 }
5792 else
5793 nodedata->enveloptheta = rightdata->enveloptheta;
5794
5795 assert(leftdata->energytheta != -1);
5796 assert(rightdata->energytheta != -1);
5797 nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5798
5799 if( leftdata->enveloplambda >= 0 )
5800 {
5801 assert(rightdata->energytheta != -1);
5802 nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5803 }
5804 else
5805 nodedata->enveloplambda = rightdata->enveloplambda;
5806
5807 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5808 nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5809
5810 SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5811
5812 if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5813 {
5814 assert(rightdata->energytheta != -1);
5815 assert(leftdata->energytheta != -1);
5816 nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5817 }
5818 else if( rightdata->energylambda >= 0 )
5819 {
5820 assert(leftdata->energytheta != -1);
5821 nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5822 }
5823 else if( leftdata->energylambda >= 0 )
5824 {
5825 assert(rightdata->energytheta != -1);
5826 nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5827 }
5828 else
5829 nodedata->energylambda = -1;
5830
5831 /* go to parent */
5832 node = SCIPbtnodeGetParent(node);
5833 }
5834
5835 SCIPdebugMsg(scip, "updating done\n");
5836}
5837
5838/** updates the key of the first parent on the trace which comes from left */
5839static
5841 SCIP_BTNODE* node, /**< node to start the trace */
5842 SCIP_Real key /**< update search key */
5843 )
5844{
5845 assert(node != NULL);
5846
5847 while( !SCIPbtnodeIsRoot(node) )
5848 {
5849 SCIP_BTNODE* parent;
5850
5851 parent = SCIPbtnodeGetParent(node);
5852 assert(parent != NULL);
5853
5854 if( SCIPbtnodeIsLeftchild(node) )
5855 {
5857
5859 assert(nodedata != NULL);
5860
5861 nodedata->key = key;
5862 return;
5863 }
5864
5865 node = parent;
5866 }
5867}
5868
5869
5870/** deletes the given node and updates all envelops */
5871static
5873 SCIP* scip, /**< SCIP data structure */
5874 SCIP_BT* tree, /**< binary tree */
5875 SCIP_BTNODE* node /**< node to be deleted */
5876 )
5877{
5878 SCIP_BTNODE* parent;
5880 SCIP_BTNODE* sibling;
5881
5882 assert(scip != NULL);
5883 assert(tree != NULL);
5884 assert(node != NULL);
5885
5886 assert(SCIPbtnodeIsLeaf(node));
5887 assert(!SCIPbtnodeIsRoot(node));
5888
5889 SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5890
5891 parent = SCIPbtnodeGetParent(node);
5892 assert(parent != NULL);
5893 if( SCIPbtnodeIsLeftchild(node) )
5894 {
5895 sibling = SCIPbtnodeGetRightchild(parent);
5897 }
5898 else
5899 {
5900 sibling = SCIPbtnodeGetLeftchild(parent);
5902 }
5903 assert(sibling != NULL);
5904
5906
5907 if( grandparent != NULL )
5908 {
5909 /* reset parent of sibling */
5911
5912 /* reset child of grandparent to sibling */
5913 if( SCIPbtnodeIsLeftchild(parent) )
5914 {
5916 }
5917 else
5918 {
5920
5923
5925
5927 }
5928
5930 }
5931 else
5932 {
5933 SCIPbtnodeSetParent(sibling, NULL);
5934
5935 SCIPbtSetRoot(tree, sibling);
5936 }
5937
5938 SCIPbtnodeFree(tree, &parent);
5939
5940 return SCIP_OKAY;
5941}
5942
5943/** moves a node form the theta set into the lambda set and updates the envelops */
5944static
5946 SCIP* scip, /**< SCIP data structure */
5947 SCIP_BT* tree, /**< binary tree */
5948 SCIP_BTNODE* node /**< node to move into the lambda set */
5949 )
5950{
5952
5953 assert(scip != NULL);
5954 assert(tree != NULL);
5955 assert(node != NULL);
5956
5958 assert(nodedata != NULL);
5959 assert(nodedata->intheta);
5960
5961 /* move the contributions form the theta set into the lambda set */
5962 assert(nodedata->enveloptheta != -1);
5963 assert(nodedata->energytheta != -1);
5964 assert(nodedata->enveloplambda == -1);
5965 assert(nodedata->energylambda == -1);
5966 nodedata->enveloplambda = nodedata->enveloptheta;
5967 nodedata->energylambda = nodedata->energytheta;
5968
5969 nodedata->enveloptheta = -1;
5970 nodedata->energytheta = 0;
5971 nodedata->intheta = FALSE;
5972
5973 /* update the energy and envelop values on trace */
5974 updateEnvelope(scip, node);
5975
5976 return SCIP_OKAY;
5977}
5978
5979/** inserts a node into the theta set and update the envelops */
5980static
5982 SCIP* scip, /**< SCIP data structure */
5983 SCIP_BT* tree, /**< binary tree */
5984 SCIP_BTNODE* node, /**< node to insert */
5985 SCIP_NODEDATA* nodedatas, /**< array of node data */
5986 int* nodedataidx, /**< array of indices for node data */
5987 int* nnodedatas /**< pointer to number of node data */
5988 )
5989{
5990 /* if the tree is empty the node will be the root node */
5991 if( SCIPbtIsEmpty(tree) )
5992 {
5993 SCIPbtSetRoot(tree, node);
5994 }
5995 else
5996 {
6000 SCIP_BTNODE* leaf;
6001 SCIP_BTNODE* newnode;
6002 SCIP_BTNODE* parent;
6003
6004 leaf = SCIPbtGetRoot(tree);
6005 assert(leaf != NULL);
6006
6008 assert(leafdata != NULL);
6009
6011 assert(nodedata != NULL);
6012 assert(nodedata->intheta);
6013
6014 /* find the position to insert the node */
6015 while( !SCIPbtnodeIsLeaf(leaf) )
6016 {
6017 if( nodedata->key < leafdata->key )
6018 leaf = SCIPbtnodeGetLeftchild(leaf);
6019 else
6020 leaf = SCIPbtnodeGetRightchild(leaf);
6021
6023 assert(leafdata != NULL);
6024 }
6025
6026 assert(leaf != NULL);
6027 assert(leaf != node);
6028
6029 /* store node data to be able to delete them latter */
6032 ++(*nnodedatas);
6033
6034 /* init node data */
6035 newnodedata->var = NULL;
6037 newnodedata->est = INT_MIN;
6038 newnodedata->lct = INT_MAX;
6039 newnodedata->duration = 0;
6040 newnodedata->demand = 0;
6041 newnodedata->enveloptheta = -1;
6042 newnodedata->energytheta = 0;
6043 newnodedata->enveloplambda = -1;
6044 newnodedata->energylambda = -1;
6045 newnodedata->idx = -1;
6046 newnodedata->intheta = TRUE;
6047
6048 /* create a new node */
6049 SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6050 assert(newnode != NULL);
6051
6052 parent = SCIPbtnodeGetParent(leaf);
6053
6054 if( parent != NULL )
6055 {
6056 SCIPbtnodeSetParent(newnode, parent);
6057
6058 /* check if the node is the left child */
6059 if( SCIPbtnodeGetLeftchild(parent) == leaf )
6060 {
6061 SCIPbtnodeSetLeftchild(parent, newnode);
6062 }
6063 else
6064 {
6065 SCIPbtnodeSetRightchild(parent, newnode);
6066 }
6067 }
6068 else
6069 SCIPbtSetRoot(tree, newnode);
6070
6071 if( nodedata->key < leafdata->key )
6072 {
6073 /* node is on the left */
6074 SCIPbtnodeSetLeftchild(newnode, node);
6075 SCIPbtnodeSetRightchild(newnode, leaf);
6076 newnodedata->key = nodedata->key;
6077 }
6078 else
6079 {
6080 /* leaf is on the left */
6081 SCIPbtnodeSetLeftchild(newnode, leaf);
6082 SCIPbtnodeSetRightchild(newnode, node);
6083 newnodedata->key = leafdata->key;
6084 }
6085
6086 SCIPbtnodeSetParent(leaf, newnode);
6087 SCIPbtnodeSetParent(node, newnode);
6088 }
6089
6090 /* update envelop */
6091 updateEnvelope(scip, node);
6092
6093 return SCIP_OKAY;
6094}
6095
6096/** returns the leaf responsible for the lambda energy */
6097static
6099 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6100 )
6101{
6102 SCIP_BTNODE* left;
6103 SCIP_BTNODE* right;
6107
6108 assert(node != NULL);
6109
6111 assert(nodedata != NULL);
6112
6113 /* check if the node is the (responsible) leaf */
6114 if( SCIPbtnodeIsLeaf(node) )
6115 {
6116 assert(!nodedata->intheta);
6117 return node;
6118 }
6119
6120 left = SCIPbtnodeGetLeftchild(node);
6121 assert(left != NULL);
6122
6124 assert(leftdata != NULL);
6125
6126 right = SCIPbtnodeGetRightchild(node);
6127 assert(right != NULL);
6128
6130 assert(rightdata != NULL);
6131
6132 assert(nodedata->energylambda != -1);
6133 assert(rightdata->energytheta != -1);
6134
6135 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6137
6138 assert(leftdata->energytheta != -1);
6139 assert(rightdata->energylambda != -1);
6140 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6141
6143}
6144
6145/** returns the leaf responsible for the lambda envelop */
6146static
6148 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6149 )
6150{
6151 SCIP_BTNODE* left;
6152 SCIP_BTNODE* right;
6156
6157 assert(node != NULL);
6158
6160 assert(nodedata != NULL);
6161
6162 /* check if the node is the (responsible) leaf */
6163 if( SCIPbtnodeIsLeaf(node) )
6164 {
6165 assert(!nodedata->intheta);
6166 return node;
6167 }
6168
6169 left = SCIPbtnodeGetLeftchild(node);
6170 assert(left != NULL);
6171
6173 assert(leftdata != NULL);
6174
6175 right = SCIPbtnodeGetRightchild(node);
6176 assert(right != NULL);
6177
6179 assert(rightdata != NULL);
6180
6181 assert(nodedata->enveloplambda != -1);
6182 assert(rightdata->energytheta != -1);
6183
6184 /* check if the left or right child is the one defining the envelop for the lambda set */
6185 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6187 else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6188 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6190
6191 assert(rightdata->enveloplambda != -1);
6192 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6193
6195}
6196
6197
6198/** reports all elements from set theta to generate a conflicting set */
6199static
6201 SCIP_BTNODE* node, /**< node within a theta subtree */
6202 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6203 int* nelements, /**< pointer to store the number of elements in omegaset */
6204 int* est, /**< pointer to store the earliest start time of the omega set */
6205 int* lct, /**< pointer to store the latest start time of the omega set */
6206 int* energy /**< pointer to store the energy of the omega set */
6207 )
6208{
6210
6212 assert(nodedata != NULL);
6213
6214 if( !SCIPbtnodeIsLeaf(node) )
6215 {
6216 collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6217 collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6218 }
6219 else if( nodedata->intheta )
6220 {
6221 assert(nodedata->var != NULL);
6222 SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6223
6224 omegaset[*nelements] = node;
6225 (*est) = MIN(*est, nodedata->est);
6226 (*lct) = MAX(*lct, nodedata->lct);
6227 (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6228 (*nelements)++;
6229 }
6230}
6231
6232
6233/** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6234static
6236 SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6237 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6238 int* nelements, /**< pointer to store the number of elements in omegaset */
6239 int* est, /**< pointer to store the earliest start time of the omega set */
6240 int* lct, /**< pointer to store the latest start time of the omega set */
6241 int* energy /**< pointer to store the energy of the omega set */
6242 )
6243{
6244 assert(node != NULL);
6245
6246 if( SCIPbtnodeIsLeaf(node) )
6247 {
6248 collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6249 }
6250 else
6251 {
6252 SCIP_BTNODE* left;
6253 SCIP_BTNODE* right;
6257
6259 assert(nodedata != NULL);
6260
6261 left = SCIPbtnodeGetLeftchild(node);
6262 assert(left != NULL);
6263
6265 assert(leftdata != NULL);
6266
6267 right = SCIPbtnodeGetRightchild(node);
6268 assert(right != NULL);
6269
6271 assert(rightdata != NULL);
6272
6274 assert(nodedata != NULL);
6275
6276 assert(nodedata->enveloptheta != -1);
6277 assert(rightdata->energytheta != -1);
6278
6279 if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6280 {
6281 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6282 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6283 }
6284 else
6285 {
6286 assert(rightdata->enveloptheta != -1);
6287 assert(nodedata->enveloptheta == rightdata->enveloptheta);
6288 traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6289 }
6290 }
6291}
6292
6293/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6294static
6296 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6297 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6298 int* nelements, /**< pointer to store the number of elements in omega set */
6299 int* est, /**< pointer to store the earliest start time of the omega set */
6300 int* lct, /**< pointer to store the latest start time of the omega set */
6301 int* energy /**< pointer to store the energy of the omega set */
6302 )
6303{
6304 SCIP_BTNODE* left;
6305 SCIP_BTNODE* right;
6309
6310 assert(node != NULL);
6311
6313 assert(nodedata != NULL);
6314
6315 /* check if the node is a leaf */
6316 if( SCIPbtnodeIsLeaf(node) )
6317 return;
6318
6319 left = SCIPbtnodeGetLeftchild(node);
6320 assert(left != NULL);
6321
6323 assert(leftdata != NULL);
6324
6325 right = SCIPbtnodeGetRightchild(node);
6326 assert(right != NULL);
6327
6329 assert(rightdata != NULL);
6330
6331 assert(nodedata->energylambda != -1);
6332 assert(rightdata->energytheta != -1);
6333
6334 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6335 {
6336 traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6337 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6338 }
6339 else
6340 {
6341 assert(leftdata->energytheta != -1);
6342 assert(rightdata->energylambda != -1);
6343 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6344
6345 collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6346 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6347 }
6348}
6349
6350/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6351static
6353 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6354 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6355 int* nelements, /**< pointer to store the number of elements in omega set */
6356 int* est, /**< pointer to store the earliest start time of the omega set */
6357 int* lct, /**< pointer to store the latest start time of the omega set */
6358 int* energy /**< pointer to store the energy of the omega set */
6359 )
6360{
6361 SCIP_BTNODE* left;
6362 SCIP_BTNODE* right;
6366
6367 assert(node != NULL);
6368
6370 assert(nodedata != NULL);
6371
6372 /* check if the node is a leaf */
6373 if( SCIPbtnodeIsLeaf(node) )
6374 {
6375 assert(!nodedata->intheta);
6376 return;
6377 }
6378
6379 left = SCIPbtnodeGetLeftchild(node);
6380 assert(left != NULL);
6381
6383 assert(leftdata != NULL);
6384
6385 right = SCIPbtnodeGetRightchild(node);
6386 assert(right != NULL);
6387
6389 assert(rightdata != NULL);
6390
6391 assert(nodedata->enveloplambda != -1);
6392 assert(rightdata->energytheta != -1);
6393
6394 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6395 {
6396 traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6397 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6398 }
6399 else
6400 {
6401 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6402 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6403 {
6404 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6405 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6406 }
6407 else
6408 {
6409 assert(rightdata->enveloplambda != -1);
6410 assert(nodedata->enveloplambda == rightdata->enveloplambda);
6411 traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6412 }
6413 }
6414}
6415
6416/** compute the energy contribution by job which corresponds to the given leaf */
6417static
6419 SCIP_BTNODE* node /**< leaf */
6420 )
6421{
6423 int duration;
6424
6426 assert(nodedata != NULL);
6427 assert(nodedata->var != NULL);
6428
6429 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6430 assert(duration > 0);
6431
6432 SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6434 SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6435
6436 /* return energy which is contributed by the start time variable */
6437 return nodedata->demand * duration;
6438}
6439
6440/** comparison method for two node data w.r.t. the earliest start time */
6441static
6443{
6444 int est1;
6445 int est2;
6446
6449
6450 return (est1 - est2);
6451}
6452
6453/** comparison method for two node data w.r.t. the latest completion time */
6454static
6456{
6458
6459 nodedatas = (SCIP_NODEDATA*) dataptr;
6460 return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6461}
6462
6463
6464/** an overload was detected; initialized conflict analysis, add an initial reason
6465 *
6466 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6467 */
6468static
6470 SCIP* scip, /**< SCIP data structure */
6471 SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6472 int capacity, /**< cumulative capacity */
6473 int nleaves, /**< number of responsible leaves */
6474 int est, /**< earliest start time of the ...... */
6475 int lct, /**< latest completly time of the .... */
6476 int reportedenergy, /**< energy which already reported */
6477 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6478 int shift, /**< shift applied to all jobs before adding them to the tree */
6479 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6480 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6481 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6482 )
6483{
6484 SCIP_Longint energy;
6485 int j;
6486
6487 /* do nothing if conflict analysis is not applicable */
6489 return SCIP_OKAY;
6490
6491 SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6492
6493 /* compute energy of initial time window */
6494 energy = ((SCIP_Longint) lct - est) * capacity;
6495
6496 /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6497 SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6498
6499 /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6500 * thereby, compute the time window of interest
6501 */
6502 for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6503 {
6505
6507 assert(nodedata != NULL);
6508
6510
6511 /* adjust energy if the earliest start time decrease */
6512 if( nodedata->est < est )
6513 {
6514 est = nodedata->est;
6515 energy = ((SCIP_Longint) lct - est) * capacity;
6516 }
6517 }
6519
6520 SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6521
6522 /* initialize conflict analysis */
6524
6525 /* flip earliest start time and latest completion time */
6526 if( !propest )
6527 {
6528 SCIPswapInts(&est, &lct);
6529
6530 /* shift earliest start time and latest completion time */
6531 lct = shift - lct;
6532 est = shift - est;
6533 }
6534 else
6535 {
6536 /* shift earliest start time and latest completion time */
6537 lct = lct + shift;
6538 est = est + shift;
6539 }
6540
6541 nleaves = j;
6542
6543 /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6544 * overloaded
6545 */
6546 for( j = nleaves-1; j >= 0; --j )
6547 {
6549
6551 assert(nodedata != NULL);
6552 assert(nodedata->var != NULL);
6553
6554 /* check if bound widening should be used */
6555 if( usebdwidening )
6556 {
6557 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6558 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6559 }
6560 else
6561 {
6564 }
6565
6566 if( explanation != NULL )
6567 explanation[nodedata->idx] = TRUE;
6568 }
6569
6570 (*initialized) = TRUE;
6571
6572 return SCIP_OKAY;
6573}
6574
6575/** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6576 * responsible interval bounds in *est_omega and *lct_omega
6577 */
6578static
6580 SCIP* scip, /**< SCIP data structure */
6581 int duration, /**< duration of the job to move */
6582 int demand, /**< demand of the job to move */
6583 int capacity, /**< cumulative capacity */
6584 int est, /**< earliest start time of the omega set */
6585 int lct, /**< latest start time of the omega set */
6586 int energy /**< energy of the omega set */
6587 )
6588{
6589 int newest;
6590
6591 newest = 0;
6592
6593 assert(scip != NULL);
6594
6595 if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6596 {
6597 if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6598 {
6599 newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6600 newest += est;
6601 }
6602 }
6603
6604 return newest;
6605}
6606
6607/** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6608 *
6609 * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6610 * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6611 */
6612static
6614 SCIP* scip, /**< SCIP data structure */
6615 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6616 SCIP_CONS* cons, /**< constraint which is propagated */
6617 SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6618 SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6619 int capacity, /**< cumulative capacity */
6620 int ncands, /**< number of candidates */
6621 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6622 int shift, /**< shift applied to all jobs before adding them to the tree */
6623 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6624 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6625 int* nchgbds, /**< pointer to store the number of bound changes */
6626 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6627 )
6628{
6630 int j;
6631
6632 assert(!SCIPbtIsEmpty(tree));
6633
6635 assert(rootdata != NULL);
6636
6637 /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6638 for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6639 {
6641
6642 if( SCIPbtnodeIsRoot(leaves[j]) )
6643 break;
6644
6646 assert(nodedata->est != -1);
6647
6648 /* check if the root lambda envelop exeeds the available capacity */
6649 while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6650 {
6652 SCIP_BTNODE* leaf;
6654 int nelements;
6655 int energy;
6656 int newest;
6657 int est;
6658 int lct;
6659
6660 assert(!(*cutoff));
6661
6662 /* find responsible leaf for the lambda envelope */
6664 assert(leaf != NULL);
6665 assert(SCIPbtnodeIsLeaf(leaf));
6666
6668 assert(leafdata != NULL);
6669 assert(!leafdata->intheta);
6670 assert(leafdata->duration > 0);
6671 assert(leafdata->est >= 0);
6672
6673 /* check if the job has to be removed since its latest completion is to large */
6674 if( leafdata->est + leafdata->duration >= nodedata->lct )
6675 {
6676 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6677
6678 /* the root might changed therefore we need to collect the new root node data */
6680 assert(rootdata != NULL);
6681
6682 continue;
6683 }
6684
6685 /* compute omega set */
6687
6688 nelements = 0;
6689 est = INT_MAX;
6690 lct = INT_MIN;
6691 energy = 0;
6692
6693 /* collect the omega set from theta set */
6694 traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6695 assert(nelements > 0);
6696 assert(nelements < ncands);
6697
6698 newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6699
6700 /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6701 if( newest > lct )
6702 {
6703 SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6704
6705 /* analyze over load */
6706 SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6707 conshdlrdata->usebdwidening, initialized, explanation) );
6708 (*cutoff) = TRUE;
6709
6710 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6712 }
6713 else if( newest > 0 )
6714 {
6715 SCIP_Bool infeasible;
6716 SCIP_Bool tightened;
6717 INFERINFO inferinfo;
6718
6719 if( propest )
6720 {
6721 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6722 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6723
6724 SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6726
6727 if( inferInfoIsValid(inferinfo) )
6728 {
6729 SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6730 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6731 }
6732 else
6733 {
6734 SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6735 TRUE, &infeasible, &tightened) );
6736 }
6737
6738 /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6740 }
6741 else
6742 {
6743 /* constuct inference information; store used propagation rule and the the time window of the omega set */
6744 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6745
6746 SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6747 SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6748
6749 if( inferInfoIsValid(inferinfo) )
6750 {
6751 SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6752 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6753 }
6754 else
6755 {
6756 SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6757 TRUE, &infeasible, &tightened) );
6758 }
6759
6760 /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6762 }
6763
6764 /* adjust the earliest start time */
6765 if( tightened )
6766 {
6767 leafdata->est = newest;
6768 (*nchgbds)++;
6769 }
6770
6771 if( infeasible )
6772 {
6773 /* initialize conflict analysis if conflict analysis is applicable */
6775 {
6776 int i;
6777
6778 SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6779
6781
6782 /* add lower and upper bound of variable which leads to the infeasibilty */
6785
6786 if( explanation != NULL )
6787 explanation[leafdata->idx] = TRUE;
6788
6789 /* add lower and upper bound of variable which lead to the infeasibilty */
6790 for( i = 0; i < nelements; ++i )
6791 {
6793 assert(nodedata != NULL);
6794
6797
6798 if( explanation != NULL )
6799 explanation[nodedata->idx] = TRUE;
6800 }
6801
6802 (*initialized) = TRUE;
6803 }
6804
6805 (*cutoff) = TRUE;
6806
6807 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6809 }
6810 }
6811
6812 /* free omegaset array */
6814
6815 /* delete responsible leaf from lambda */
6816 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6817
6818 /* the root might changed therefore we need to collect the new root node data */
6820 assert(rootdata != NULL);
6821 }
6822
6823 /* move current job j from the theta set into the lambda set */
6824 SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6825 }
6826
6827 return SCIP_OKAY;
6828}
6829
6830/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6831 *
6832 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6833 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6834 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6835 */
6836static
6838 SCIP* scip, /**< SCIP data structure */
6839 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6840 int nvars, /**< number of start time variables (activities) */
6841 SCIP_VAR** vars, /**< array of start time variables */
6842 int* durations, /**< array of durations */
6843 int* demands, /**< array of demands */
6844 int capacity, /**< cumulative capacity */
6845 int hmin, /**< left bound of time axis to be considered (including hmin) */
6846 int hmax, /**< right bound of time axis to be considered (not including hmax) */
6847 SCIP_CONS* cons, /**< constraint which is propagated */
6848 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6849 SCIP_Bool* initialized, /**< was conflict analysis initialized */
6850 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6851 int* nchgbds, /**< pointer to store the number of bound changes */
6852 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6853 )
6854{
6856 SCIP_BTNODE** leaves;
6857 SCIP_BT* tree;
6858 int* nodedataidx;
6859
6860 int totalenergy;
6861 int nnodedatas;
6862 int ninsertcands;
6863 int ncands;
6864
6865 int shift;
6866 int idx = -1;
6867 int j;
6868
6869 assert(scip != NULL);
6870 assert(cons != NULL);
6871 assert(initialized != NULL);
6872 assert(cutoff != NULL);
6873 assert(*cutoff == FALSE);
6874
6875 SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6876
6880
6881 ncands = 0;
6882 totalenergy = 0;
6883
6885
6886 /* compute the shift which we apply to compute .... latest completion time of all jobs */
6887 if( propest )
6888 shift = 0;
6889 else
6890 {
6891 shift = 0;
6892
6893 /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6894 * earliest start time propagation to handle the latest completion times
6895 */
6896 for( j = 0; j < nvars; ++j )
6897 {
6898 int lct;
6899
6900 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6901 shift = MAX(shift, lct);
6902 }
6903 }
6904
6905 /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6906 * horizon
6907 */
6908 for( j = 0; j < nvars; ++j )
6909 {
6911 SCIP_VAR* var;
6912 int duration;
6913 int leftadjust;
6914 int rightadjust;
6915 int energy;
6916 int est;
6917 int lct;
6918
6919 var = vars[j];
6920 assert(var != NULL);
6921
6922 duration = durations[j];
6923 assert(duration > 0);
6924
6925 leftadjust = 0;
6926 rightadjust = 0;
6927
6929 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6930
6931 /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6932 * effective horizon [hmin,hmax)
6933 */
6934 if( conshdlrdata->useadjustedjobs )
6935 {
6936 if( est < hmin )
6937 {
6938 leftadjust = (hmin - est);
6939 est = hmin;
6940 }
6941 if( lct > hmax )
6942 {
6943 rightadjust = (lct - hmax);
6944 lct = hmax;
6945 }
6946
6947 /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6948 * with the effective time horizon
6949 */
6950 if( duration - leftadjust - rightadjust <= 0 )
6951 continue;
6952 }
6953 else if( est < hmin || lct > hmax )
6954 continue;
6955
6956 energy = demands[j] * (duration - leftadjust - rightadjust);
6957 assert(energy > 0);
6958
6960
6961 /* flip earliest start time and latest completion time */
6962 if( !propest )
6963 {
6964 SCIPswapInts(&est, &lct);
6965
6966 /* shift earliest start time and latest completion time */
6967 lct = shift - lct;
6968 est = shift - est;
6969 }
6970 else
6971 {
6972 /* shift earliest start time and latest completion time */
6973 lct = lct - shift;
6974 est = est - shift;
6975 }
6976 assert(est < lct);
6977 assert(est >= 0);
6978 assert(lct >= 0);
6979
6980 /* create search node data */
6981 nodedata = &nodedatas[ncands];
6982 nodedataidx[ncands] = ncands;
6983 ++ncands;
6984
6985 /* initialize search node data */
6986 /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6987 nodedata->key = est + j / (2.0 * nvars);
6988 nodedata->var = var;
6989 nodedata->est = est;
6990 nodedata->lct = lct;
6991 nodedata->demand = demands[j];
6992 nodedata->duration = duration;
6993 nodedata->leftadjust = leftadjust;
6994 nodedata->rightadjust = rightadjust;
6995
6996 /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6997 * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6998 * particular time interval [a,b] against the time interval [0,b].
6999 */
7000 nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
7001 nodedata->energytheta = energy;
7002 nodedata->enveloplambda = -1;
7003 nodedata->energylambda = -1;
7004
7005 nodedata->idx = j;
7006 nodedata->intheta = TRUE;
7007 }
7008
7009 nnodedatas = ncands;
7010
7011 /* sort (non-decreasing) the jobs w.r.t. latest completion times */
7013
7014 ninsertcands = 0;
7015
7016 /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
7017 * the root envelop detects an overload
7018 */
7019 for( j = 0; j < ncands; ++j )
7020 {
7021 SCIP_BTNODE* leaf;
7023
7024 idx = nodedataidx[j];
7025
7026 /* check if the new job opens a time window which size is so large that it offers more energy than the total
7027 * energy of all candidate jobs. If so we skip that one.
7028 */
7029 if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
7030 {
7031 /* set the earliest start time to minus one to mark that candidate to be not used */
7032 nodedatas[idx].est = -1;
7033 continue;
7034 }
7035
7036 /* create search node */
7037 SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
7038
7039 /* insert new node into the theta set and updete the envelops */
7041 assert(nnodedatas <= 2*nvars);
7042
7043 /* move the inserted candidates together */
7044 leaves[ninsertcands] = leaf;
7045 ninsertcands++;
7046
7047 assert(!SCIPbtIsEmpty(tree));
7049 assert(rootdata != NULL);
7050
7051 /* check if the theta set envelops exceeds the available capacity */
7052 if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
7053 {
7054 SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
7055 (*cutoff) = TRUE;
7056
7057 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
7059
7060 break;
7061 }
7062 }
7063
7064 /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7065 if( *cutoff )
7066 {
7067 int glbenery;
7068 int est;
7069 int lct;
7070
7071 glbenery = 0;
7072 assert( 0 <= idx );
7073 est = nodedatas[idx].est;
7074 lct = nodedatas[idx].lct;
7075
7076 /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7077 * which led to an overload
7078 */
7079 for( j = j+1; j < ncands; ++j )
7080 {
7082 int duration;
7083 int glbest;
7084 int glblct;
7085
7086 idx = nodedataidx[j];
7087 nodedata = &nodedatas[idx];
7088 assert(nodedata != NULL);
7089
7090 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7091
7092 /* get latest start time */
7095
7096 /* check if parts of the jobs run with the time window defined by the last inserted job */
7097 if( glbest < est )
7098 duration -= (est - glbest);
7099
7100 if( glblct > lct )
7101 duration -= (glblct - lct);
7102
7103 if( duration > 0 )
7104 {
7105 glbenery += nodedata->demand * duration;
7106
7107 if( explanation != NULL )
7108 explanation[nodedata->idx] = TRUE;
7109 }
7110 }
7111
7112 /* analyze the overload */
7113 SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7114 conshdlrdata->usebdwidening, initialized, explanation) );
7115 }
7116 else if( ninsertcands > 1 && conshdlrdata->efinfer )
7117 {
7118 /* if we have more than one job insterted and edge-finding should be performed we do it */
7119 SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7120 propest, shift, initialized, explanation, nchgbds, cutoff) );
7121 }
7122
7123 /* free theta tree */
7124 SCIPbtFree(&tree);
7125
7126 /* free buffer arrays */
7127 SCIPfreeBufferArray(scip, &leaves);
7130
7131 return SCIP_OKAY;
7132}
7133
7134/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7135 *
7136 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7137 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7138 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7139 */
7140static
7142 SCIP* scip, /**< SCIP data structure */
7143 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7144 int nvars, /**< number of start time variables (activities) */
7145 SCIP_VAR** vars, /**< array of start time variables */
7146 int* durations, /**< array of durations */
7147 int* demands, /**< array of demands */
7148 int capacity, /**< cumulative capacity */
7149 int hmin, /**< left bound of time axis to be considered (including hmin) */
7150 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7151 SCIP_CONS* cons, /**< constraint which is propagated */
7152 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7153 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7154 int* nchgbds, /**< pointer to store the number of bound changes */
7155 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7156 )
7157{
7158 /* check if a cutoff was already detected */
7159 if( (*cutoff) )
7160 return SCIP_OKAY;
7161
7162 /* check if at least the basic overload checking should be preformed */
7163 if( !conshdlrdata->efcheck )
7164 return SCIP_OKAY;
7165
7166 /* check for overload, which may result in a cutoff */
7167 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7168 cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7169
7170 /* check if a cutoff was detected */
7171 if( (*cutoff) )
7172 return SCIP_OKAY;
7173
7174 /* check if bound should be infer */
7175 if( !conshdlrdata->efinfer )
7176 return SCIP_OKAY;
7177
7178 /* check for overload, which may result in a cutoff */
7179 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7180 cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7181
7182 return SCIP_OKAY;
7183}
7184
7185/** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7186 * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7187 * event points
7188 */
7189static
7191 SCIP* scip, /**< SCIP data structure */
7192 int nvars, /**< number of start time variables (activities) */
7193 SCIP_VAR** vars, /**< array of start time variables */
7194 int* durations, /**< array of durations */
7195 int* demands, /**< array of demands */
7196 int capacity, /**< cumulative capacity */
7197 int hmin, /**< left bound of time axis to be considered (including hmin) */
7198 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7199 SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7200 )
7201{
7202 SCIP_VAR* var;
7203 int* starttimes; /* stores when each job is starting */
7204 int* endtimes; /* stores when each job ends */
7205 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7206 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7207
7208 int lb;
7209 int ub;
7210 int freecapacity; /* remaining capacity */
7211 int curtime; /* point in time which we are just checking */
7212 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7213 int njobs;
7214 int j;
7215
7216 assert(scip != NULL);
7217 assert(redundant != NULL);
7218
7219 (*redundant) = TRUE;
7220
7221 /* if no activities are associated with this cumulative then this constraint is redundant */
7222 if( nvars == 0 )
7223 return SCIP_OKAY;
7224
7225 assert(vars != NULL);
7226
7229 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7231
7232 njobs = 0;
7233
7234 /* assign variables, start and endpoints to arrays */
7235 for( j = 0; j < nvars; ++j )
7236 {
7237 assert(durations[j] > 0);
7238 assert(demands[j] > 0);
7239
7240 var = vars[j];
7241 assert(var != NULL);
7242
7245
7246 /* check if jobs runs completely outside of the effective time horizon */
7247 if( lb >= hmax || ub + durations[j] <= hmin )
7248 continue;
7249
7250 starttimes[njobs] = MAX(lb, hmin);
7251 startindices[njobs] = j;
7252
7253 endtimes[njobs] = MIN(ub + durations[j], hmax);
7254 endindices[njobs] = j;
7255 assert(starttimes[njobs] <= endtimes[njobs]);
7256 njobs++;
7257 }
7258
7259 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7260 SCIPsortIntInt(starttimes, startindices, njobs);
7262
7263 endindex = 0;
7264 freecapacity = capacity;
7265
7266 /* check each start point of a job whether the capacity is violated or not */
7267 for( j = 0; j < njobs; ++j )
7268 {
7269 curtime = starttimes[j];
7270
7271 /* stop checking, if time point is above hmax */
7272 if( curtime >= hmax )
7273 break;
7274
7275 /* subtract all capacity needed up to this point */
7276 freecapacity -= demands[startindices[j]];
7277 while( j+1 < njobs && starttimes[j+1] == curtime )
7278 {
7279 ++j;
7280 freecapacity -= demands[startindices[j]];
7281 }
7282
7283 /* free all capacity usages of jobs the are no longer running */
7284 while( endtimes[endindex] <= curtime )
7285 {
7286 freecapacity += demands[endindices[endindex]];
7287 ++endindex;
7288 }
7289 assert(freecapacity <= capacity);
7290
7291 /* check freecapacity to be smaller than zero */
7293 {
7294 (*redundant) = FALSE;
7295 break;
7296 }
7297 } /*lint --e{850}*/
7298
7299 /* free all buffer arrays */
7301 SCIPfreeBufferArray(scip, &startindices);
7304
7305 return SCIP_OKAY;
7306}
7307
7308/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7309 * completion time
7310 */
7311static
7313 SCIP* scip, /**< SCIP data structure */
7314 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7315 SCIP_PROFILE* profile, /**< resource profile */
7316 int nvars, /**< number of variables (jobs) */
7317 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7318 int* durations, /**< array containing corresponding durations */
7319 int* demands, /**< array containing corresponding demands */
7320 int capacity, /**< cumulative capacity */
7321 int hmin, /**< left bound of time axis to be considered (including hmin) */
7322 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7323 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7324 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7325 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7326 )
7327{
7328 int v;
7329
7330 /* insert all cores */
7331 for( v = 0; v < nvars; ++v )
7332 {
7333 SCIP_VAR* var;
7334 SCIP_Bool infeasible;
7335 int duration;
7336 int demand;
7337 int begin;
7338 int end;
7339 int est;
7340 int lst;
7341 int pos;
7342
7343 var = vars[v];
7344 assert(var != NULL);
7347
7348 duration = durations[v];
7349 assert(duration > 0);
7350
7351 demand = demands[v];
7352 assert(demand > 0);
7353
7354 /* collect earliest and latest start time */
7357
7358 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7359 if( lst + duration <= hmin || est >= hmax )
7360 continue;
7361
7362 /* compute core interval w.r.t. effective time horizon */
7363 begin = MAX(hmin, lst);
7364 end = MIN(hmax, est + duration);
7365
7366 /* check if a core exists */
7367 if( begin >= end )
7368 continue;
7369
7370 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7371 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7372
7373 /* insert the core into core resource profile (complexity O(log n)) */
7374 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7375
7376 /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7377 if( infeasible )
7378 {
7379 assert(begin <= SCIPprofileGetTime(profile, pos));
7380 assert(end > SCIPprofileGetTime(profile, pos));
7381
7382 /* use conflict analysis to analysis the core insertion which was infeasible */
7383 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7384 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7385
7386 if( explanation != NULL )
7387 explanation[v] = TRUE;
7388
7389 (*cutoff) = TRUE;
7390
7391 /* for the statistic we count the number of times a cutoff was detected due the time-time */
7393
7394 break;
7395 }
7396 }
7397
7398 return SCIP_OKAY;
7399}
7400
7401/** propagate the cumulative condition */
7402static
7404 SCIP* scip, /**< SCIP data structure */
7405 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7406 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7407 int nvars, /**< number of start time variables (activities) */
7408 SCIP_VAR** vars, /**< array of start time variables */
7409 int* durations, /**< array of durations */
7410 int* demands, /**< array of demands */
7411 int capacity, /**< cumulative capacity */
7412 int hmin, /**< left bound of time axis to be considered (including hmin) */
7413 int hmax, /**< right bound of time axis to be considered (not including hmax) */
7414 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7415 int* nchgbds, /**< pointer to store the number of bound changes */
7416 SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7417 SCIP_Bool* initialized, /**< was conflict analysis initialized */
7418 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7419 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7420 )
7421{
7422 SCIP_PROFILE* profile;
7423
7424 SCIP_RETCODE retcode = SCIP_OKAY;
7425
7426 assert(nchgbds != NULL);
7427 assert(initialized != NULL);
7428 assert(cutoff != NULL);
7429 assert(!(*cutoff));
7430
7431 /**@todo avoid always sorting the variable array */
7432
7433 /* check if the constraint is redundant */
7434 SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7435
7436 if( *redundant )
7437 return SCIP_OKAY;
7438
7439 /* create an empty resource profile for profiling the cores of the jobs */
7440 SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7441
7442 /* create core profile (compulsory parts) */
7443 SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7444 initialized, explanation, cutoff), TERMINATE );
7445
7446 /* propagate the job cores until nothing else can be detected */
7447 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7448 {
7449 SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7450 nchgbds, initialized, explanation, cutoff), TERMINATE );
7451 }
7452
7453 /* run edge finding propagator */
7454 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7455 {
7456 SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7457 cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7458 }
7459
7460 /* run time-table edge-finding propagator */
7461 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7462 {
7463 SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7464 nchgbds, initialized, explanation, cutoff), TERMINATE );
7465 }
7466 /* free resource profile */
7467TERMINATE:
7468 SCIPprofileFree(&profile);
7469
7470 return retcode;
7471}
7472
7473/** propagate the cumulative constraint */
7474static
7476 SCIP* scip, /**< SCIP data structure */
7477 SCIP_CONS* cons, /**< constraint to propagate */
7478 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7479 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7480 int* nchgbds, /**< pointer to store the number of bound changes */
7481 int* ndelconss, /**< pointer to store the number of deleted constraints */
7482 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7483 )
7484{
7485 SCIP_CONSDATA* consdata;
7486 SCIP_Bool initialized;
7487 SCIP_Bool redundant;
7488 int oldnchgbds;
7489
7490 assert(scip != NULL);
7491 assert(cons != NULL);
7492
7493 consdata = SCIPconsGetData(cons);
7494 assert(consdata != NULL);
7495
7496 oldnchgbds = *nchgbds;
7497 initialized = FALSE;
7498 redundant = FALSE;
7499
7500 if( SCIPconsIsDeleted(cons) )
7501 {
7503 return SCIP_OKAY;
7504 }
7505
7506 /* if the constraint marked to be propagated, do nothing */
7507 if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7508 return SCIP_OKAY;
7509
7510 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7511 consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7512 consdata->hmin, consdata->hmax, cons,
7513 nchgbds, &redundant, &initialized, NULL, cutoff) );
7514
7515 if( redundant )
7516 {
7517 SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7518 SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7519
7520 if( !SCIPinProbing(scip) )
7521 {
7523 (*ndelconss)++;
7524 }
7525 }
7526 else
7527 {
7528 if( initialized )
7529 {
7530 /* run conflict analysis since it was initialized */
7531 assert(*cutoff == TRUE);
7532 SCIPdebugMsg(scip, "start conflict analysis\n");
7534 }
7535
7536 /* if successful, reset age of constraint */
7537 if( *cutoff || *nchgbds > oldnchgbds )
7538 {
7540 }
7541 else
7542 {
7543 /* mark the constraint to be propagated */
7544 consdata->propagated = TRUE;
7545 }
7546 }
7547
7548 return SCIP_OKAY;
7549}
7550
7551/** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7552 * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7553 * be realize as domain reduction. Otherwise we do nothing
7554 */
7555static
7557 SCIP* scip, /**< SCIP data structure */
7558 SCIP_VAR** vars, /**< problem variables */
7559 int nvars, /**< number of problem variables */
7560 int probingpos, /**< variable number to apply probing on */
7561 SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7562 SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7563 SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7564 SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7565 SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7566 SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7567 SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7568 SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7569 SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7570 SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7571 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7572 SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7573 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7574 )
7575{
7576 SCIP_VAR* var;
7577 SCIP_Bool tightened;
7578
7579 assert(probingpos >= 0);
7581 assert(success != NULL);
7582 assert(cutoff != NULL);
7583
7584 var = vars[probingpos];
7585 assert(var != NULL);
7590
7591 (*success) = FALSE;
7592
7594 return SCIP_OKAY;
7595
7596 /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7599
7600 if( (*cutoff) )
7601 {
7602 /* note that cutoff may occur if presolving has not been executed fully */
7603 SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7604
7605 if( tightened )
7606 {
7607 (*success) =TRUE;
7608 (*nfixedvars)++;
7609 }
7610
7611 return SCIP_OKAY;
7612 }
7613
7614 /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7615 * presolving has not been executed fully
7616 */
7618 {
7619 /* note that cutoff may occur if presolving has not been executed fully */
7620 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7621
7622 if( tightened )
7623 {
7624 (*success) = TRUE;
7625 (*nfixedvars)++;
7626 }
7627
7628 return SCIP_OKAY;
7629 }
7630
7631 /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7634
7635 if( (*cutoff) )
7636 {
7637 /* note that cutoff may occur if presolving has not been executed fully */
7638 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7639
7640 if( tightened )
7641 {
7642 (*success) =TRUE;
7643 (*nfixedvars)++;
7644 }
7645
7646 return SCIP_OKAY;
7647 }
7648
7649 return SCIP_OKAY;
7650}
7651
7652/** is it possible, to round variable down w.r.t. objective function */
7653static
7655 SCIP* scip, /**< SCIP data structure */
7656 SCIP_VAR* var, /**< problem variable */
7657 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7658 )
7659{
7660 SCIP_Real objval;
7661 int scalar;
7662
7663 assert(roundable != NULL);
7664
7665 *roundable = TRUE;
7666
7667 /* a fixed variable can be definition always be safely rounded */
7669 return SCIP_OKAY;
7670
7671 /* in case the variable is not active we need to check the object coefficient of the active variable */
7672 if( !SCIPvarIsActive(var) )
7673 {
7675 int constant;
7676
7677 actvar = var;
7678
7679 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7680 assert(scalar != 0);
7681
7682 objval = scalar * SCIPvarGetObj(actvar);
7683 } /*lint !e438*/
7684 else
7685 {
7686 scalar = 1;
7688 }
7689
7690 /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7691 * (the transformed problem is always a minimization problem)
7692 *
7693 * @note that we need to check this condition w.r.t. active variable space
7694 */
7695 if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7696 *roundable = FALSE;
7697
7698 return SCIP_OKAY;
7699}
7700
7701/** is it possible, to round variable up w.r.t. objective function */
7702static
7704 SCIP* scip, /**< SCIP data structure */
7705 SCIP_VAR* var, /**< problem variable */
7706 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7707 )
7708{
7709 SCIP_Real objval;
7710 int scalar;
7711
7712 assert(roundable != NULL);
7713
7714 *roundable = TRUE;
7715
7716 /* a fixed variable can be definition always be safely rounded */
7718 return SCIP_OKAY;
7719
7720 /* in case the variable is not active we need to check the object coefficient of the active variable */
7721 if( !SCIPvarIsActive(var) )
7722 {
7724 int constant;
7725
7726 actvar = var;
7727
7728 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7729 assert(scalar != 0);
7730
7731 objval = scalar * SCIPvarGetObj(actvar);
7732 } /*lint !e438*/
7733 else
7734 {
7735 scalar = 1;
7737 }
7738
7739 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7740 * (the transformed problem is always a minimization problem)
7741 *
7742 * @note that we need to check this condition w.r.t. active variable space
7743 */
7744 if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7745 *roundable = FALSE;
7746
7747 return SCIP_OKAY;
7748}
7749
7750/** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7751 * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7752 * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7753 * the only one locking this variable in the corresponding direction.
7754 */
7755static
7757 SCIP* scip, /**< SCIP data structure */
7758 SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7759 int nconss, /**< number of cumulative constraints */
7760 SCIP_Bool local, /**< use local bounds effective horizon? */
7761 int* alternativelbs, /**< alternative lower bounds */
7762 int* alternativeubs, /**< alternative lower bounds */
7763 int* downlocks, /**< number of constraints with down lock participating by the computation */
7764 int* uplocks /**< number of constraints with up lock participating by the computation */
7765 )
7766{
7767 int nvars;
7768 int c;
7769 int v;
7770
7771 for( c = 0; c < nconss; ++c )
7772 {
7773 SCIP_CONSDATA* consdata;
7774 SCIP_CONS* cons;
7775 SCIP_VAR* var;
7776 int hmin;
7777 int hmax;
7778
7779 cons = conss[c];
7780 assert(cons != NULL);
7781
7782 /* ignore constraints which are already deletet and those which are not check constraints */
7783 if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7784 continue;
7785
7786 consdata = SCIPconsGetData(cons);
7787 assert(consdata != NULL);
7788 assert(consdata->nvars > 1);
7789
7790 /* compute the hmin and hmax */
7791 if( local )
7792 {
7793 SCIP_PROFILE* profile;
7794 SCIP_RETCODE retcode;
7795
7796 /* create empty resource profile with infinity resource capacity */
7797 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7798
7799 /* create worst case resource profile */
7800 retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7801
7802 hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7803 hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7804
7805 /* free worst case profile */
7806 SCIPprofileFree(&profile);
7807
7808 if( retcode != SCIP_OKAY )
7809 return retcode;
7810 }
7811 else
7812 {
7813 hmin = consdata->hmin;
7814 hmax = consdata->hmax;
7815 }
7816
7817 consdata = SCIPconsGetData(cons);
7818 assert(consdata != NULL);
7819
7820 nvars = consdata->nvars;
7821
7822 for( v = 0; v < nvars; ++v )
7823 {
7824 int scalar;
7825 int constant;
7826 int idx;
7827
7828 var = consdata->vars[v];
7829 assert(var != NULL);
7830
7831 /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7833
7834 /* ignore variable locally fixed variables */
7836 continue;
7837
7838 SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7839 idx = SCIPvarGetProbindex(var);
7840 assert(idx >= 0);
7841
7842 /* first check lower bound fixing */
7843 if( consdata->downlocks[v] )
7844 {
7845 int ect;
7846 int est;
7847
7848 /* the variable has a down locked */
7849 est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7850 ect = est + consdata->durations[v];
7851
7852 if( ect <= hmin || hmin >= hmax )
7853 downlocks[idx]++;
7854 else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7855 {
7856 alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7857 downlocks[idx]++;
7858 }
7859 }
7860
7861 /* second check upper bound fixing */
7862 if( consdata->uplocks[v] )
7863 {
7864 int duration;
7865 int lct;
7866 int lst;
7867
7868 duration = consdata->durations[v];
7869
7870 /* the variable has a up lock locked */
7871 lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7872 lct = lst + duration;
7873
7874 if( lst >= hmax || hmin >= hmax )
7875 uplocks[idx]++;
7876 else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7877 {
7878 alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7879 uplocks[idx]++;
7880 }
7881 }
7882 }
7883 }
7884
7885 return SCIP_OKAY;
7886}
7887
7888/** apply all fixings which are given by the alternative bounds */
7889static
7891 SCIP* scip, /**< SCIP data structure */
7892 SCIP_VAR** vars, /**< array of active variables */
7893 int nvars, /**< number of active variables */
7894 int* alternativelbs, /**< alternative lower bounds */
7895 int* alternativeubs, /**< alternative lower bounds */
7896 int* downlocks, /**< number of constraints with down lock participating by the computation */
7897 int* uplocks, /**< number of constraints with up lock participating by the computation */
7898 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7899 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7900 )
7901{
7902 SCIP_Real* downimpllbs;
7903 SCIP_Real* downimplubs;
7904 SCIP_Real* downproplbs;
7905 SCIP_Real* downpropubs;
7906 SCIP_Real* upimpllbs;
7907 SCIP_Real* upimplubs;
7908 SCIP_Real* upproplbs;
7909 SCIP_Real* uppropubs;
7910 int v;
7911
7912 /* get temporary memory for storing probing results */
7921
7922 for( v = 0; v < nvars; ++v )
7923 {
7924 SCIP_VAR* var;
7925 SCIP_Bool infeasible;
7926 SCIP_Bool fixed;
7927 SCIP_Bool roundable;
7928 int ub;
7929 int lb;
7930
7931 var = vars[v];
7932 assert(var != NULL);
7933
7934 /* ignore variables for which no alternative bounds have been computed */
7935 if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7936 continue;
7937
7940
7941 /* ignore fixed variables */
7942 if( ub - lb <= 0 )
7943 continue;
7944
7945 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7946 {
7948
7949 if( roundable )
7950 {
7951 if( alternativelbs[v] > ub )
7952 {
7953 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7954 assert(!infeasible);
7955 assert(fixed);
7956
7957 (*nfixedvars)++;
7958
7959 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7960 * constraints
7961 */
7963 }
7964 else
7965 {
7966 SCIP_Bool success;
7967
7968 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7969 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7970 * infeasible we can apply the dual reduction; otherwise we do nothing
7971 */
7972 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7974 nfixedvars, &success, cutoff) );
7975
7976 if( success )
7977 {
7979 }
7980 }
7981 }
7982 }
7983
7986
7987 /* ignore fixed variables */
7988 if( ub - lb <= 0 )
7989 continue;
7990
7991 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7992 {
7994
7995 if( roundable )
7996 {
7997 if( alternativeubs[v] < lb )
7998 {
7999 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
8000 assert(!infeasible);
8001 assert(fixed);
8002
8003 (*nfixedvars)++;
8004
8005 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
8006 * constraints
8007 */
8009 }
8010 else
8011 {
8012 SCIP_Bool success;
8013
8014 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
8015 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
8016 * infeasible we can apply the dual reduction; otherwise we do nothing
8017 */
8018 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
8020 nfixedvars, &success, cutoff) );
8021
8022 if( success )
8023 {
8025 }
8026 }
8027 }
8028 }
8029 }
8030
8031 /* free temporary memory */
8040
8041 return SCIP_OKAY;
8042}
8043
8044/** propagate all constraints together */
8045static
8047 SCIP* scip, /**< SCIP data structure */
8048 SCIP_CONS** conss, /**< all cumulative constraint */
8049 int nconss, /**< number of cumulative constraints */
8050 SCIP_Bool local, /**< use local bounds effective horizon? */
8051 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
8052 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
8053 SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
8054 )
8055{ /*lint --e{715}*/
8056 SCIP_VAR** vars;
8057 int* downlocks;
8058 int* uplocks;
8059 int* alternativelbs;
8060 int* alternativeubs;
8061 int oldnfixedvars;
8062 int nvars;
8063 int v;
8064
8066 return SCIP_OKAY;
8067
8069 oldnfixedvars = *nfixedvars;
8070
8072 SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8076
8077 /* initialize arrays */
8078 for( v = 0; v < nvars; ++v )
8079 {
8080 downlocks[v] = 0;
8081 uplocks[v] = 0;
8084 }
8085
8086 /* compute alternative bounds */
8087 SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8088
8089 /* apply fixing which result of the alternative bounds directly */
8091 nfixedvars, cutoff) );
8092
8093 if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8094 {
8096 }
8097
8098 /* free all buffers */
8101 SCIPfreeBufferArray(scip, &uplocks);
8102 SCIPfreeBufferArray(scip, &downlocks);
8104
8105 return SCIP_OKAY;
8106}
8107
8108/**@} */
8109
8110/**@name Linear relaxations
8111 *
8112 * @{
8113 */
8114
8115/** creates covering cuts for jobs violating resource constraints */
8116static
8118 SCIP* scip, /**< SCIP data structure */
8119 SCIP_CONS* cons, /**< constraint to be checked */
8120 int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8121 int time /**< at this point in time covering constraints are valid */
8122 )
8123{
8124 SCIP_CONSDATA* consdata;
8125 SCIP_ROW* row;
8126 int* flexibleids;
8127 int* demands;
8128
8129 char rowname[SCIP_MAXSTRLEN];
8130
8131 int remainingcap;
8132 int smallcoversize; /* size of a small cover */
8133 int bigcoversize; /* size of a big cover */
8134 int nvars;
8135
8136 int nflexible;
8137 int sumdemand; /* demand of all jobs up to a certain index */
8138 int j;
8139
8140 assert(cons != NULL);
8141
8142 /* get constraint data structure */
8143 consdata = SCIPconsGetData(cons);
8144 assert(consdata != NULL );
8145
8146 nvars = consdata->nvars;
8147
8148 /* sort jobs according to demands */
8151
8152 nflexible = 0;
8153 remainingcap = consdata->capacity;
8154
8155 /* get all jobs intersecting point 'time' with their bounds */
8156 for( j = 0; j < nvars; ++j )
8157 {
8158 int ub;
8159
8160 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8161
8162 /* only add jobs to array if they intersect with point 'time' */
8163 if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8164 {
8165 /* if job is fixed, capacity has to be decreased */
8166 if( startvalues[j] == ub )
8167 {
8168 remainingcap -= consdata->demands[j];
8169 }
8170 else
8171 {
8172 demands[nflexible] = consdata->demands[j];
8174 ++nflexible;
8175 }
8176 }
8177 }
8178 assert(remainingcap >= 0);
8179
8180 /* sort demands and job ids */
8182
8183 /*
8184 * version 1:
8185 * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8186 * erzeuge cover constraint
8187 *
8188 */
8189
8190 /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8191 sumdemand = 0;
8192 j = 0;
8193
8194 while( j < nflexible && sumdemand <= remainingcap )
8195 {
8196 sumdemand += demands[j];
8197 j++;
8198 }
8199
8200 /* j jobs form a conflict, set coversize to 'j - 1' */
8201 bigcoversize = j-1;
8204
8205 /* - create a row for all jobs and their binary variables.
8206 * - at most coversize many binary variables of jobs can be set to one
8207 */
8208
8209 /* construct row name */
8210 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8212 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8214
8215 for( j = 0; j < nflexible; ++j )
8216 {
8217 SCIP_VAR** binvars;
8218 SCIP_Real* vals;
8219 int nbinvars;
8220 int idx;
8221 int start;
8222 int end;
8223 int lb;
8224 int ub;
8225 int b;
8226
8227 idx = flexibleids[j];
8228
8229 /* get and add binvars into var array */
8230 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8231 assert(nbinvars != 0);
8232
8233 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8234 assert(vals != NULL);
8235
8236 lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8237 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8238
8239 /* compute start and finishing time */
8240 start = time - consdata->durations[idx] + 1;
8241 end = MIN(time, ub);
8242
8243 /* add all neccessary binary variables */
8244 for( b = 0; b < nbinvars; ++b )
8245 {
8246 if( vals[b] < start || vals[b] < lb )
8247 continue;
8248
8249 if( vals[b] > end )
8250 break;
8251
8252 assert(binvars[b] != NULL);
8253 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8254 }
8255 }
8256
8257 /* insert and release row */
8259
8260 if( consdata->bcoverrowssize == 0 )
8261 {
8262 consdata->bcoverrowssize = 10;
8263 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8264 }
8265 if( consdata->nbcoverrows == consdata->bcoverrowssize )
8266 {
8267 consdata->bcoverrowssize *= 2;
8268 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8269 }
8270
8271 consdata->bcoverrows[consdata->nbcoverrows] = row;
8272 consdata->nbcoverrows++;
8273
8274 /*
8275 * version 2:
8276 * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8277 * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8278 */
8279 /* find maximum number of jobs that can run in parallel (= coversize -1) */
8280 sumdemand = 0;
8281 j = nflexible -1;
8282 while( sumdemand <= remainingcap )
8283 {
8284 assert(j >= 0);
8285 sumdemand += demands[j];
8286 j--;
8287 }
8288
8289 smallcoversize = nflexible - (j + 1) - 1;
8290 while( j > 0 && demands[j] == demands[nflexible-1] )
8291 --j;
8292
8294
8295 if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8296 {
8297 /* construct row name */
8298 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8300 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8302
8303 /* filter binary variables for each unfixed job */
8304 for( j = j + 1; j < nflexible; ++j )
8305 {
8306 SCIP_VAR** binvars;
8307 SCIP_Real* vals;
8308 int nbinvars;
8309 int idx;
8310 int start;
8311 int end;
8312 int lb;
8313 int ub;
8314 int b;
8315
8316 idx = flexibleids[j];
8317
8318 /* get and add binvars into var array */
8319 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8320 assert(nbinvars != 0);
8321
8322 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8323 assert(vals != NULL);
8324
8325 lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8326 ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8327
8328 /* compute start and finishing time */
8329 start = time - consdata->durations[idx] + 1;
8330 end = MIN(time, ub);
8331
8332 /* add all neccessary binary variables */
8333 for( b = 0; b < nbinvars; ++b )
8334 {
8335 if( vals[b] < start || vals[b] < lb )
8336 continue;
8337
8338 if( vals[b] > end )
8339 break;
8340
8341 assert(binvars[b] != NULL);
8342 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8343 }
8344 }
8345
8346 /* insert and release row */
8348 if( consdata->scoverrowssize == 0 )
8349 {
8350 consdata->scoverrowssize = 10;
8351 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8352 }
8353 if( consdata->nscoverrows == consdata->scoverrowssize )
8354 {
8355 consdata->scoverrowssize *= 2;
8356 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8357 }
8358
8359 consdata->scoverrows[consdata->nscoverrows] = row;
8360 consdata->nscoverrows++;
8361 }
8362
8363 /* free buffer arrays */
8365 SCIPfreeBufferArray(scip, &demands);
8366
8367 return SCIP_OKAY;
8368}
8369
8370/** method to construct cover cuts for all points in time */
8371static
8373 SCIP* scip, /**< SCIP data structure */
8374 SCIP_CONS* cons /**< constraint to be separated */
8375 )
8376{
8377 SCIP_CONSDATA* consdata;
8378
8379 int* startvalues; /* stores when each job is starting */
8380 int* endvalues; /* stores when each job ends */
8381 int* startvaluessorted; /* stores when each job is starting */
8382 int* endvaluessorted; /* stores when each job ends */
8383 int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8384 int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8385
8386 int nvars; /* number of jobs for this constraint */
8387 int freecapacity; /* remaining capacity */
8388 int curtime; /* point in time which we are just checking */
8389 int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8390
8391 int hmin;
8392 int hmax;
8393
8394 int j;
8395 int t;
8396
8397 assert(scip != NULL);
8398 assert(cons != NULL);
8399
8400 consdata = SCIPconsGetData(cons);
8401 assert(consdata != NULL);
8402
8403 /* if no activities are associated with this resource then this constraint is redundant */
8404 if( consdata->vars == NULL )
8405 return SCIP_OKAY;
8406
8407 nvars = consdata->nvars;
8408 hmin = consdata->hmin;
8409 hmax = consdata->hmax;
8410
8415 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8417
8418 /* assign start and endpoints to arrays */
8419 for ( j = 0; j < nvars; ++j )
8420 {
8423
8424 endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8426
8427 startindices[j] = j;
8428 endindices[j] = j;
8429 }
8430
8431 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8432 * (and sort the indices in the same way) */
8433 SCIPsortIntInt(startvaluessorted, startindices, nvars);
8435
8436 endidx = 0;
8437 freecapacity = consdata->capacity;
8438
8439 /* check each startpoint of a job whether the capacity is kept or not */
8440 for( j = 0; j < nvars; ++j )
8441 {
8443 if( curtime >= hmax )
8444 break;
8445
8446 /* subtract all capacity needed up to this point */
8447 freecapacity -= consdata->demands[startindices[j]];
8448
8449 while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8450 {
8451 ++j;
8452 freecapacity -= consdata->demands[startindices[j]];
8453 }
8454
8455 /* free all capacity usages of jobs the are no longer running */
8457 {
8458 freecapacity += consdata->demands[endindices[endidx]];
8459 ++endidx;
8460 }
8461
8463 assert(endidx <= nvars);
8464
8465 /* --> endindex - points to the next job which will finish
8466 * j - points to the last job that has been released
8467 */
8468
8469 /* check freecapacity to be smaller than zero
8470 * then we will add cover constraints to the MIP
8471 */
8473 {
8475
8476 /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8477 if( j < nvars-1 )
8479 else
8481
8483
8484 for( t = curtime; t < nextprofilechange; ++t )
8485 {
8486 SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8487
8488 /* create covering constraint */
8490 }
8491 } /* end if freecapacity > 0 */
8492 } /*lint --e{850}*/
8493
8494 consdata->covercuts = TRUE;
8495
8496 /* free all buffer arrays */
8498 SCIPfreeBufferArray(scip, &startindices);
8503
8504 return SCIP_OKAY;
8505}
8506
8507/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8508 * constraint
8509 */
8510static
8512 SCIP* scip, /**< SCIP data structure */
8513 SCIP_CONS* cons, /**< constraint to be checked */
8514 int* startindices, /**< permutation with rspect to the start times */
8515 int curtime, /**< current point in time */
8516 int nstarted, /**< number of jobs that start before the curtime or at curtime */
8517 int nfinished, /**< number of jobs that finished before curtime or at curtime */
8518 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8519 )
8520{
8521 SCIP_CONSDATA* consdata;
8522 SCIP_VAR** binvars;
8523 int* coefs;
8524 int nbinvars;
8525 char name[SCIP_MAXSTRLEN];
8526 int capacity;
8527 int b;
8528
8530
8531 consdata = SCIPconsGetData(cons);
8532 assert(consdata != NULL);
8533 assert(consdata->nvars > 0);
8534
8535 capacity = consdata->capacity;
8536 assert(capacity > 0);
8537
8538 nbinvars = 0;
8539 SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8540
8541 /* construct row name */
8542 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8543
8544 if( cutsasconss )
8545 {
8546 SCIP_CONS* lincons;
8547
8548 /* create knapsack constraint for the given time point */
8549 SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8551
8552 for( b = 0; b < nbinvars; ++b )
8553 {
8554 SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8555 }
8556
8557 /* add and release the new constraint */
8558 SCIP_CALL( SCIPaddCons(scip, lincons) );
8559 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8560 }
8561 else
8562 {
8563 SCIP_ROW* row;
8564
8565 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8567
8568 for( b = 0; b < nbinvars; ++b )
8569 {
8570 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8571 }
8572
8575
8576 if( consdata->demandrowssize == 0 )
8577 {
8578 consdata->demandrowssize = 10;
8579 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8580 }
8581 if( consdata->ndemandrows == consdata->demandrowssize )
8582 {
8583 consdata->demandrowssize *= 2;
8584 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8585 }
8586
8587 consdata->demandrows[consdata->ndemandrows] = row;
8588 consdata->ndemandrows++;
8589 }
8590
8591 SCIPfreeBufferArrayNull(scip, &binvars);
8593
8594 return SCIP_OKAY;
8595}
8596
8597/** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8598 * row
8599 */
8600static
8602 SCIP* scip, /**< SCIP data structure */
8603 SCIP_CONS* cons, /**< constraint to be checked */
8604 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8605 )
8606{
8607 SCIP_CONSDATA* consdata;
8608
8609 int* starttimes; /* stores when each job is starting */
8610 int* endtimes; /* stores when each job ends */
8611 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8612 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8613
8614 int nvars; /* number of activities for this constraint */
8615 int freecapacity; /* remaining capacity */
8616 int curtime; /* point in time which we are just checking */
8617 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8618
8619 int hmin;
8620 int hmax;
8621
8622 int j;
8623
8624 assert(scip != NULL);
8625 assert(cons != NULL);
8626
8627 consdata = SCIPconsGetData(cons);
8628 assert(consdata != NULL);
8629
8630 nvars = consdata->nvars;
8631
8632 /* if no activities are associated with this cumulative then this constraint is redundant */
8633 if( nvars == 0 )
8634 return SCIP_OKAY;
8635
8636 assert(consdata->vars != NULL);
8637
8640 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8642
8643 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8644 SCIPconsGetName(cons), nvars);
8645
8646 /* create event point arrays */
8647 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8648 starttimes, endtimes, startindices, endindices, FALSE);
8649
8650 endindex = 0;
8651 freecapacity = consdata->capacity;
8652 hmin = consdata->hmin;
8653 hmax = consdata->hmax;
8654
8655 /* check each startpoint of a job whether the capacity is kept or not */
8656 for( j = 0; j < nvars; ++j )
8657 {
8658 curtime = starttimes[j];
8659 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8660
8661 if( curtime >= hmax )
8662 break;
8663
8664 /* remove the capacity requirments for all job which start at the curtime */
8665 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8666
8667 /* add the capacity requirments for all job which end at the curtime */
8669
8671 assert(endindex <= nvars);
8672
8673 /* endindex - points to the next job which will finish */
8674 /* j - points to the last job that has been released */
8675
8676 /* if free capacity is smaller than zero, then add rows to the LP */
8678 {
8679 int nextstarttime;
8680 int t;
8681
8682 /* step forward until next job is released and see whether capacity constraint is met or not */
8683 if( j < nvars-1 )
8685 else
8687
8689
8690 /* create capacity restriction row for current event point */
8691 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8692
8693 /* create for all points in time between the current event point and next start event point a row if the free
8694 * capacity is still smaller than zero */
8695 for( t = curtime+1 ; t < nextstarttime; ++t )
8696 {
8697 /* add the capacity requirments for all job which end at the curtime */
8699
8700 if( freecapacity < 0 )
8701 {
8702 /* add constraint */
8703 SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8704
8705 /* create capacity restriction row */
8706 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8707 }
8708 else
8709 break;
8710 }
8711 }
8712 } /*lint --e{850}*/
8713
8714 /* free all buffer arrays */
8716 SCIPfreeBufferArray(scip, &startindices);
8719
8720 return SCIP_OKAY;
8721}
8722
8723/** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8724 * capacity is larger than the capacity of the cumulative constraint
8725 * - for each necessary point in time:
8726 *
8727 * sum_j sum_t demand_j * x_{j,t} <= capacity
8728 *
8729 * where x(j,t) is the binary variables of job j at time t
8730 */
8731static
8733 SCIP* scip, /**< SCIP data structure */
8734 SCIP_CONS* cons, /**< cumulative constraint */
8735 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8736 )
8737{
8738 SCIP_CONSDATA* consdata;
8739
8740 consdata = SCIPconsGetData(cons);
8741 assert(consdata != NULL);
8742 assert(consdata->demandrows == NULL);
8743 assert(consdata->ndemandrows == 0);
8744
8745 /* collect the linking constraints */
8746 if( consdata->linkingconss == NULL )
8747 {
8749 }
8750
8751 SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8752
8753 /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8754 if( cutsasconss )
8755 {
8756 if( SCIPconsIsInitial(cons) )
8757 {
8759 }
8760 if( SCIPconsIsSeparated(cons) )
8761 {
8763 }
8764 if( SCIPconsIsEnforced(cons) )
8765 {
8767 }
8768 }
8769
8770 return SCIP_OKAY;
8771}
8772
8773/** adds linear relaxation of cumulative constraint to the LP */
8774static
8776 SCIP* scip, /**< SCIP data structure */
8777 SCIP_CONS* cons, /**< cumulative constraint */
8778 SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8779 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8780 )
8781{
8782 SCIP_CONSDATA* consdata;
8783 int r;
8784
8785 consdata = SCIPconsGetData(cons);
8786 assert(consdata != NULL);
8787
8788 if( consdata->demandrows == NULL )
8789 {
8790 assert(consdata->ndemandrows == 0);
8791
8792 SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8793
8794 return SCIP_OKAY;
8795 }
8796
8797 for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8798 {
8799 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8800 {
8801 assert(consdata->demandrows[r] != NULL);
8802 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8803 }
8804 }
8805
8806 return SCIP_OKAY;
8807}
8808
8809/** checks constraint for violation, and adds it as a cut if possible */
8810static
8812 SCIP* scip, /**< SCIP data structure */
8813 SCIP_CONS* cons, /**< cumulative constraint to be separated */
8814 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8815 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8816 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8817 )
8818{ /*lint --e{715}*/
8819 SCIP_CONSDATA* consdata;
8820 int ncuts;
8821 int r;
8822
8823 assert(scip != NULL);
8824 assert(cons != NULL);
8825 assert(separated != NULL);
8826 assert(cutoff != NULL);
8827
8828 *separated = FALSE;
8829 *cutoff = FALSE;
8830
8831 consdata = SCIPconsGetData(cons);
8832 assert(consdata != NULL);
8833
8834 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8835
8836 if( consdata->demandrows == NULL )
8837 {
8838 assert(consdata->ndemandrows == 0);
8839
8841
8842 return SCIP_OKAY;
8843 }
8844
8845 ncuts = 0;
8846
8847 /* check each row that is not contained in LP */
8848 for( r = 0; r < consdata->ndemandrows; ++r )
8849 {
8850 if( !SCIProwIsInLP(consdata->demandrows[r]) )
8851 {
8852 SCIP_Real feasibility;
8853
8854 if( sol != NULL )
8855 feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8856 else
8857 feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8858
8860 {
8861 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8862 if ( *cutoff )
8863 {
8865 return SCIP_OKAY;
8866 }
8867 *separated = TRUE;
8868 ncuts++;
8869 }
8870 }
8871 }
8872
8873 if( ncuts > 0 )
8874 {
8875 SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8876
8877 /* if successful, reset age of constraint */
8879 (*separated) = TRUE;
8880 }
8881
8882 return SCIP_OKAY;
8883}
8884
8885/** checks constraint for violation, and adds it as a cut if possible */
8886static
8888 SCIP* scip, /**< SCIP data structure */
8889 SCIP_CONS* cons, /**< logic or constraint to be separated */
8890 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8891 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8892 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8893 )
8894{
8895 SCIP_CONSDATA* consdata;
8896 SCIP_ROW* row;
8897 SCIP_Real minfeasibility;
8898 int r;
8899
8900 assert(scip != NULL);
8901 assert(cons != NULL);
8902 assert(separated != NULL);
8903 assert(cutoff != NULL);
8904
8905 *separated = FALSE;
8906 *cutoff = FALSE;
8907
8908 consdata = SCIPconsGetData(cons);
8909 assert(consdata != NULL);
8910
8911 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8912
8913 /* collect the linking constraints */
8914 if( consdata->linkingconss == NULL )
8915 {
8917 }
8918
8919 if( !consdata->covercuts )
8920 {
8921 SCIP_CALL( createCoverCuts(scip, cons) );
8922 }
8923
8924 row = NULL;
8926
8927 /* check each row of small covers that is not contained in LP */
8928 for( r = 0; r < consdata->nscoverrows; ++r )
8929 {
8930 if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8931 {
8932 SCIP_Real feasibility;
8933
8934 assert(consdata->scoverrows[r] != NULL);
8935 if( sol != NULL )
8936 feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8937 else
8938 feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8939
8941 {
8943 row = consdata->scoverrows[r];
8944 }
8945 }
8946 }
8947
8949
8950 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8951 {
8952 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8954
8957 if ( *cutoff )
8958 return SCIP_OKAY;
8959 (*separated) = TRUE;
8960 }
8961
8963 row = NULL;
8964
8965 /* check each row of small covers that is not contained in LP */
8966 for( r = 0; r < consdata->nbcoverrows; ++r )
8967 {
8968 if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8969 {
8970 SCIP_Real feasibility;
8971
8972 assert(consdata->bcoverrows[r] != NULL);
8973 if( sol != NULL )
8974 feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8975 else
8976 feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8977
8979 {
8981 row = consdata->bcoverrows[r];
8982 }
8983 }
8984 }
8985
8987
8988 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8989 {
8990 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8992
8993 assert(row != NULL);
8996 if ( *cutoff )
8997 return SCIP_OKAY;
8998 (*separated) = TRUE;
8999 }
9000
9001 return SCIP_OKAY;
9002}
9003
9004/** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
9005static
9007 SCIP* scip, /**< SCIP data structure */
9008 SCIP_CONS* cons, /**< constraint to be checked */
9009 int* startindices, /**< permutation with rspect to the start times */
9010 int curtime, /**< current point in time */
9011 int nstarted, /**< number of jobs that start before the curtime or at curtime */
9012 int nfinished, /**< number of jobs that finished before curtime or at curtime */
9013 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
9014 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9015 )
9016{
9017 SCIP_CONSDATA* consdata;
9018 char name[SCIP_MAXSTRLEN];
9019 int lhs; /* left hand side of constraint */
9020
9022 SCIP_ROW* row;
9023
9024 int v;
9025
9027
9028 consdata = SCIPconsGetData(cons);
9029 assert(consdata != NULL);
9030 assert(consdata->nvars > 0);
9031
9033
9034 SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
9035
9036 if( lower )
9037 {
9038 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
9039
9040 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
9041 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9042 }
9043 else
9044 {
9045 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
9046 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
9047 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9048 }
9049
9051
9052 for( v = 0; v < nstarted - nfinished; ++v )
9053 {
9054 SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9055 }
9056
9059
9060 SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
9061
9062 SCIP_CALL( SCIPreleaseRow(scip, &row) );
9063
9064 /* free buffers */
9066
9067 return SCIP_OKAY;
9068}
9069
9070/** checks constraint for violation, and adds it as a cut if possible */
9071static
9073 SCIP* scip, /**< SCIP data structure */
9074 SCIP_CONS* cons, /**< cumulative constraint to be separated */
9075 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9076 SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9077 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9078 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9079 )
9080{
9081 SCIP_CONSDATA* consdata;
9082
9083 int* starttimes; /* stores when each job is starting */
9084 int* endtimes; /* stores when each job ends */
9085 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9086 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9087
9088 int nvars; /* number of activities for this constraint */
9089 int freecapacity; /* remaining capacity */
9090 int curtime; /* point in time which we are just checking */
9091 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9092
9093 int hmin;
9094 int hmax;
9095 int j;
9096
9097 assert(scip != NULL);
9098 assert(cons != NULL);
9099
9100 consdata = SCIPconsGetData(cons);
9101 assert(consdata != NULL);
9102
9103 nvars = consdata->nvars;
9104
9105 /* if no activities are associated with this cumulative then this constraint is redundant */
9106 if( nvars <= 1 )
9107 return SCIP_OKAY;
9108
9109 assert(consdata->vars != NULL);
9110
9113 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9115
9116 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9117 SCIPconsGetName(cons), nvars);
9118
9119 /* create event point arrays */
9121
9122 /* now nvars might be smaller than before! */
9123
9124 endindex = 0;
9125 freecapacity = consdata->capacity;
9126 hmin = consdata->hmin;
9127 hmax = consdata->hmax;
9128
9129 /* check each startpoint of a job whether the capacity is kept or not */
9130 for( j = 0; j < nvars && !(*cutoff); ++j )
9131 {
9132 curtime = starttimes[j];
9133
9134 if( curtime >= hmax )
9135 break;
9136
9137 /* remove the capacity requirements for all job which start at the curtime */
9138 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9139
9140 /* add the capacity requirments for all job which end at the curtime */
9142
9144 assert(endindex <= nvars);
9145
9146 /* endindex - points to the next job which will finish */
9147 /* j - points to the last job that has been released */
9148
9149 /* if free capacity is smaller than zero, then add rows to the LP */
9151 {
9152 /* create capacity restriction row for current event point */
9154 *separated = TRUE;
9155 }
9156 } /*lint --e{850}*/
9157
9158 /* free all buffer arrays */
9160 SCIPfreeBufferArray(scip, &startindices);
9163
9164 return SCIP_OKAY;
9165}
9166
9167/**@} */
9168
9169
9170/**@name Presolving
9171 *
9172 * @{
9173 */
9174
9175#ifndef NDEBUG
9176/** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9177 * correct
9178 */
9179static
9181 SCIP* scip, /**< SCIP data structure */
9182 SCIP_CONS* cons /**< constraint to be checked */
9183 )
9184{
9185 SCIP_CONSDATA* consdata;
9186 int capacity;
9187 int nvars;
9188 int j;
9189
9190 assert(scip != NULL);
9191 assert(cons != NULL);
9192
9193 consdata = SCIPconsGetData(cons);
9194 assert(consdata != NULL);
9195
9196 nvars = consdata->nvars;
9197
9198 /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9199 if( nvars <= 1 )
9200 return TRUE;
9201
9202 assert(consdata->vars != NULL);
9203 capacity = consdata->capacity;
9204
9205 /* check each activity: if demand is larger than capacity the problem is infeasible */
9206 for ( j = 0; j < nvars; ++j )
9207 {
9208 if( consdata->demands[j] > capacity )
9209 return FALSE;
9210 }
9211
9212 return TRUE;
9213}
9214#endif
9215
9216/** delete constraint if it consists of at most one job
9217 *
9218 * @todo this method needs to be adjusted w.r.t. effective horizon
9219 */
9220static
9222 SCIP* scip, /**< SCIP data structure */
9223 SCIP_CONS* cons, /**< constraint to propagate */
9224 int* ndelconss, /**< pointer to store the number of deleted constraints */
9225 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9226 )
9227{
9228 SCIP_CONSDATA* consdata;
9229
9230 assert(scip != NULL);
9231 assert(cons != NULL);
9232
9233 consdata = SCIPconsGetData(cons);
9234 assert(consdata != NULL);
9235
9236 if( consdata->nvars == 0 )
9237 {
9238 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9239
9240 SCIP_CALL( SCIPdelCons(scip, cons) );
9241 (*ndelconss)++;
9242 }
9243 else if( consdata->nvars == 1 )
9244 {
9245 if( consdata->demands[0] > consdata->capacity )
9246 (*cutoff) = TRUE;
9247 else
9248 {
9249 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9250
9251 SCIP_CALL( SCIPdelCons(scip, cons) );
9252 (*ndelconss)++;
9253 }
9254 }
9255
9256 return SCIP_OKAY;
9257}
9258
9259/** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9260 * this is done in the SCIP_DECL_CONSINITPRE() callback
9261 */
9262static
9264 SCIP* scip, /**< SCIP data structure */
9265 SCIP_CONS* cons /**< constraint to propagate */
9266 )
9267{
9268 SCIP_CONSDATA* consdata;
9269 SCIP_VAR* var;
9270 int demand;
9271 int duration;
9272 int hmin;
9273 int hmax;
9274 int est;
9275 int lct;
9276 int j;
9277
9278 assert(scip != NULL);
9279 assert(cons != NULL);
9280
9281 consdata = SCIPconsGetData(cons);
9282 assert(consdata != NULL);
9283
9284 hmin = consdata->hmin;
9285 hmax = consdata->hmax;
9286
9287 SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9288 SCIPconsGetName(cons), hmin, hmax);
9289
9290 for( j = consdata->nvars-1; j >= 0; --j )
9291 {
9292 var = consdata->vars[j];
9293 demand = consdata->demands[j];
9294 duration = consdata->durations[j];
9295
9296 /* earliest completion time (ect) and latest start time (lst) */
9298 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9299
9300 if( demand == 0 || duration == 0 )
9301 {
9302 /* jobs with zero demand or zero duration can be removed */
9303 SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9304 SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9305
9306 /* remove variable form constraint */
9307 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9308 }
9309 else if( est >= hmax || lct <= hmin )
9310 {
9311 SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9312 SCIPvarGetName(var), est, lct - duration, duration);
9313
9314 /* delete variable at the given position */
9315 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9316
9317 /* for the statistic we count the number of jobs which are irrelevant */
9319 }
9320 }
9321
9322 return SCIP_OKAY;
9323}
9324
9325/** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9326static
9328 SCIP* scip, /**< SCIP data structure */
9329 SCIP_CONSDATA* consdata, /**< constraint data */
9330 int pos, /**< position of job in the consdata */
9331 int* nchgbds, /**< pointer to store the number of changed bounds */
9332 int* naddconss, /**< pointer to store the number of added constraints */
9333 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9334 )
9335{
9336 SCIP_VAR* var;
9337 SCIP_Bool tightened;
9338 int duration;
9339 int ect;
9340 int lst;
9341
9342 assert(scip != NULL);
9343
9344 /* zero energy jobs should be removed already */
9345 assert(consdata->durations[pos] > 0);
9346 assert(consdata->demands[pos] > 0);
9347
9348 var = consdata->vars[pos];
9349 assert(var != NULL);
9350 duration = consdata->durations[pos];
9351
9352 /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9353 SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9354 SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9355
9356 /* earliest completion time (ect) and latest start time (lst) */
9359
9360 /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9361 if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9362 return SCIP_OKAY;
9363
9364 if( ect > consdata->hmin && lst < consdata->hmax )
9365 {
9366 /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9367 *cutoff = TRUE;
9368 }
9369 else if( lst < consdata->hmax )
9370 {
9371 /* move the latest start time of this job in such a way that it finishes before or at hmin */
9372 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9373 assert(tightened);
9374 assert(!(*cutoff));
9375 (*nchgbds)++;
9376 }
9377 else if( ect > consdata->hmin )
9378 {
9379 /* move the earliest start time of this job in such a way that it starts after or at hmax */
9380 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9381 assert(tightened);
9382 assert(!(*cutoff));
9383 (*nchgbds)++;
9384 }
9385 else
9386 {
9387 /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9388 * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9389 *
9390 * (var <= hmin - duration) /\ (var >= hmax)
9391 */
9392 SCIP_CONS* cons;
9393
9394 SCIP_VAR* vartuple[2];
9396 SCIP_Real boundtuple[2];
9397
9398 char name[SCIP_MAXSTRLEN];
9399 int leftbound;
9400 int rightbound;
9401
9402 leftbound = consdata->hmin - duration;
9403 rightbound = consdata->hmax;
9404
9405 /* allocate temporary memory for arrays */
9406 vartuple[0] = var;
9407 vartuple[1] = var;
9412
9413 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9415
9416 /* create and add bounddisjunction constraint */
9418 TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9419
9421
9422 /* add and release the new constraint */
9423 SCIP_CALL( SCIPaddCons(scip, cons) );
9424 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9425 (*naddconss)++;
9426 }
9427
9428 return SCIP_OKAY;
9429}
9430
9431/** try to removed over sizeed jobs (the demand is larger than the capacity) */
9432static
9434 SCIP* scip, /**< SCIP data structure */
9435 SCIP_CONS* cons, /**< constraint */
9436 int* nchgbds, /**< pointer to store the number of changed bounds */
9437 int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9438 int* naddconss, /**< pointer to store the number of added constraints */
9439 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9440 )
9441{
9442 SCIP_CONSDATA* consdata;
9443 int capacity;
9444 int j;
9445
9446 consdata = SCIPconsGetData(cons);
9447 assert(consdata != NULL);
9448
9449 /* if a cutoff was already detected just return */
9450 if( *cutoff )
9451 return SCIP_OKAY;
9452
9453 capacity = consdata->capacity;
9454
9455 for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9456 {
9457 if( consdata->demands[j] > capacity )
9458 {
9459 SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9460
9461 /* remove variable form constraint */
9462 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9463 (*nchgcoefs)++;
9464 }
9465 }
9466
9467 SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9468
9469 return SCIP_OKAY;
9470}
9471
9472/** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9473static
9475 SCIP* scip, /**< SCIP data structure */
9476 SCIP_VAR* var, /**< integer variable to fix */
9477 SCIP_Bool uplock, /**< has thet start time variable a up lock */
9478 int* nfixedvars /**< pointer to store the number fixed variables */
9479 )
9480{
9481 SCIP_Bool infeasible;
9482 SCIP_Bool tightened;
9483 SCIP_Bool roundable;
9484
9485 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9486 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9487 */
9489 return SCIP_OKAY;
9490
9491 /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9492 * handler is the only one locking that variable up
9493 */
9494 assert(uplock == TRUE || uplock == FALSE);
9495 assert((int)TRUE == 1); /*lint !e506*/
9496 assert((int)FALSE == 0); /*lint !e506*/
9497
9499 return SCIP_OKAY;
9500
9502
9503 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9504 * (the transformed problem is always a minimization problem)
9505 */
9506 if( !roundable )
9507 return SCIP_OKAY;
9508
9509 SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9511
9512 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9513 assert(!infeasible);
9514
9515 if( tightened )
9516 {
9517 SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9518 (*nfixedvars)++;
9519 }
9520
9521 return SCIP_OKAY;
9522}
9523
9524/** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9525static
9527 SCIP* scip, /**< SCIP data structure */
9528 SCIP_VAR* var, /**< integer variable to fix */
9529 SCIP_Bool downlock, /**< has the variable a down lock */
9530 int* nfixedvars /**< pointer to store the number fixed variables */
9531 )
9532{
9533 SCIP_Bool infeasible;
9534 SCIP_Bool tightened;
9535 SCIP_Bool roundable;
9536
9537 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9538 * would/could end in an implication which can lead to cutoff of the/all optimal solution
9539 */
9541 return SCIP_OKAY;
9542
9543 /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9544 * handler is the only one locking that variable down
9545 */
9546 assert(downlock == TRUE || downlock == FALSE);
9547 assert((int)TRUE == 1); /*lint !e506*/
9548 assert((int)FALSE == 0); /*lint !e506*/
9549
9551 return SCIP_OKAY;
9552
9554
9555 /* is it possible, to round variable down w.r.t. objective function? */
9556 if( !roundable )
9557 return SCIP_OKAY;
9558
9559 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9560 assert(!infeasible);
9561
9562 if( tightened )
9563 {
9564 SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9565 (*nfixedvars)++;
9566 }
9567
9568 return SCIP_OKAY;
9569}
9570
9571/** normalize cumulative condition */
9572static
9574 SCIP* scip, /**< SCIP data structure */
9575 int nvars, /**< number of start time variables (activities) */
9576 int* demands, /**< array of demands */
9577 int* capacity, /**< pointer to store the changed cumulative capacity */
9578 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9579 int* nchgsides /**< pointer to count number of side changes */
9580 )
9581{ /*lint --e{715}*/
9582 SCIP_Longint gcd;
9583 int mindemand1;
9584 int mindemand2;
9585 int v;
9586
9587 if( *capacity == 1 || nvars <= 1 )
9588 return;
9589
9590 assert(demands[nvars-1] <= *capacity);
9591 assert(demands[nvars-2] <= *capacity);
9592
9593 gcd = (SCIP_Longint)demands[nvars-1];
9594 mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9595 mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9596
9597 for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9598 {
9600 assert(demands[v] <= *capacity);
9601
9602 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9603
9604 if( mindemand1 > demands[v] )
9605 {
9607 mindemand1 = demands[v];
9608 }
9609 else if( mindemand2 > demands[v] )
9610 mindemand2 = demands[v];
9611 }
9612
9613 if( mindemand1 + mindemand2 > *capacity )
9614 {
9615 SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9616
9617 for( v = 0; v < nvars; ++v )
9618 demands[v] = 1;
9619
9620 (*capacity) = 1;
9621
9622 (*nchgcoefs) += nvars;
9623 (*nchgsides)++;
9624 }
9625 else if( gcd >= 2 )
9626 {
9627 SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9628
9629 for( v = 0; v < nvars; ++v )
9630 demands[v] /= (int) gcd;
9631
9632 (*capacity) /= (int) gcd;
9633
9634 (*nchgcoefs) += nvars;
9635 (*nchgsides)++;
9636 }
9637}
9638
9639/** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9640 * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9641 * capacity since in that case none of the jobs can run in parallel
9642 */
9643static
9645 SCIP* scip, /**< SCIP data structure */
9646 SCIP_CONS* cons, /**< cumulative constraint */
9647 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9648 int* nchgsides /**< pointer to count number of side changes */
9649 )
9650{
9651 SCIP_CONSDATA* consdata;
9652 int capacity;
9653
9654 assert(nchgcoefs != NULL);
9655 assert(nchgsides != NULL);
9657
9658 consdata = SCIPconsGetData(cons);
9659 assert(consdata != NULL);
9660
9661 if( consdata->normalized )
9662 return;
9663
9664 capacity = consdata->capacity;
9665
9666 /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9667
9668 normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9669
9670 consdata->normalized = TRUE;
9671
9672 if( capacity > consdata->capacity )
9673 consdata->varbounds = FALSE;
9674}
9675
9676/** computes for the given cumulative condition the effective horizon */
9677static
9679 SCIP* scip, /**< SCIP data structure */
9680 int nvars, /**< number of variables (jobs) */
9681 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9682 int* durations, /**< array containing corresponding durations */
9683 int* demands, /**< array containing corresponding demands */
9684 int capacity, /**< available cumulative capacity */
9685 int* hmin, /**< pointer to store the left bound of the effective horizon */
9686 int* hmax, /**< pointer to store the right bound of the effective horizon */
9687 int* split /**< point were the cumulative condition can be split */
9688 )
9689{
9690 SCIP_PROFILE* profile;
9691
9692 /* create empty resource profile with infinity resource capacity */
9693 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9694
9695 /* create worst case resource profile */
9696 SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9697
9698 /* print resource profile in if SCIP_DEBUG is defined */
9700
9701 /* computes the first time point where the resource capacity can be violated */
9702 (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9703
9704 /* computes the first time point where the resource capacity is satisfied for sure */
9705 (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9706
9707 (*split) = (*hmax);
9708
9709 if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9710 {
9711 int* timepoints;
9712 int* loads;
9713 int ntimepoints;
9714 int t;
9715
9716 /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9717 * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9718 * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9719 * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9720 * explain the certain "old" bound changes
9721 */
9722
9723 /* search for time points */
9724 ntimepoints = SCIPprofileGetNTimepoints(profile);
9725 timepoints = SCIPprofileGetTimepoints(profile);
9726 loads = SCIPprofileGetLoads(profile);
9727
9728 /* check if there exist a time point within the effective horizon [hmin,hmax) such that the capacity is not exceed w.r.t. worst case profile */
9729 for( t = 0; t < ntimepoints; ++t )
9730 {
9731 /* ignore all time points before the effective horizon */
9732 if( timepoints[t] <= *hmin )
9733 continue;
9734
9735 /* ignore all time points after the effective horizon */
9736 if( timepoints[t] >= *hmax )
9737 break;
9738
9739 /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9740 * can split the cumulative constraint into two cumulative constraints
9741 */
9742 if( loads[t] <= capacity )
9743 {
9744 (*split) = timepoints[t];
9745 break;
9746 }
9747 }
9748 }
9749
9750 /* free worst case profile */
9751 SCIPprofileFree(&profile);
9752
9753 return SCIP_OKAY;
9754}
9755
9756/** creates and adds a cumulative constraint */
9757static
9759 SCIP* scip, /**< SCIP data structure */
9760 const char* name, /**< name of constraint */
9761 int nvars, /**< number of variables (jobs) */
9762 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9763 int* durations, /**< array containing corresponding durations */
9764 int* demands, /**< array containing corresponding demands */
9765 int capacity, /**< available cumulative capacity */
9766 int hmin, /**< left bound of time axis to be considered (including hmin) */
9767 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9768 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9769 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9770 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9771 * Usually set to TRUE. */
9772 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9773 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9774 SCIP_Bool check, /**< should the constraint be checked for feasibility?
9775 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9776 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9777 * Usually set to TRUE. */
9778 SCIP_Bool local, /**< is constraint only valid locally?
9779 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9780 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9781 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9782 * adds coefficients to this constraint. */
9783 SCIP_Bool dynamic, /**< is constraint subject to aging?
9784 * Usually set to FALSE. Set to TRUE for own cuts which
9785 * are seperated as constraints. */
9786 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9787 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9788 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9789 * if it may be moved to a more global node?
9790 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9791 )
9792{
9793 SCIP_CONS* cons;
9794
9795 /* creates cumulative constraint and adds it to problem */
9796 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9797 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9798
9799 /* adjust the effective time horizon of the new constraint */
9800 SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9801 SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9802
9803 /* add and release new cumulative constraint */
9804 SCIP_CALL( SCIPaddCons(scip, cons) );
9805 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9806
9807 return SCIP_OKAY;
9808}
9809
9810/** computes the effective horizon and checks if the constraint can be decompsed */
9811static
9813 SCIP* scip, /**< SCIP data structure */
9814 SCIP_CONS* cons, /**< cumulative constraint */
9815 int* ndelconss, /**< pointer to store the number of deleted constraints */
9816 int* naddconss, /**< pointer to store the number of added constraints */
9817 int* nchgsides /**< pointer to store the number of changed sides */
9818 )
9819{
9820 SCIP_CONSDATA* consdata;
9821 int hmin;
9822 int hmax;
9823 int split;
9824
9825 consdata = SCIPconsGetData(cons);
9826 assert(consdata != NULL);
9827
9828 if( consdata->nvars <= 1 )
9829 return SCIP_OKAY;
9830
9831 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9832 consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9833
9834 /* check if this time point improves the effective horizon */
9835 if( consdata->hmin < hmin )
9836 {
9837 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9838
9839 consdata->hmin = hmin;
9840 (*nchgsides)++;
9841 }
9842
9843 /* check if this time point improves the effective horizon */
9844 if( consdata->hmax > hmax )
9845 {
9846 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9847 consdata->hmax = hmax;
9848 (*nchgsides)++;
9849 }
9850
9851 /* check if the constraint is redundant */
9852 if( consdata->hmax <= consdata->hmin )
9853 {
9854 SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9855 SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9856
9857 SCIP_CALL( SCIPdelCons(scip, cons) );
9858 (*ndelconss)++;
9859 }
9860 else if( consdata->hmin < split && split < consdata->hmax )
9861 {
9862 char name[SCIP_MAXSTRLEN];
9863 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9864
9865 SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9866 SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9867
9869
9870 /* creates cumulative constraint and adds it to problem */
9871 SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9872 consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9875
9876 /* adjust the effective time horizon of the constraint */
9877 consdata->hmax = split;
9878
9879 assert(consdata->hmin < consdata->hmax);
9880
9881 /* for the statistic we count the number of time we decompose a cumulative constraint */
9883 (*naddconss)++;
9884 }
9885
9886 return SCIP_OKAY;
9887}
9888
9889
9890/** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9891 *
9892 * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9893 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9894 *
9895 * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9896 * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9897 * down-lock of the corresponding start time variable can be removed.
9898 *
9899 * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9900 * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9901 * negative, than the job can be dual fixed to its earlier start time (est).
9902 *
9903 * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9904 * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9905 * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9906 *
9907 * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9908 * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9909 * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9910 * form variable domain is dual feasible.
9911 *
9912 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9913 * the cumulative condition; The deletion has to be done later.
9914 */
9915static
9917 SCIP* scip, /**< SCIP data structure */
9918 int nvars, /**< number of start time variables (activities) */
9919 SCIP_VAR** vars, /**< array of start time variables */
9920 int* durations, /**< array of durations */
9921 int hmin, /**< left bound of time axis to be considered (including hmin) */
9922 int hmax, /**< right bound of time axis to be considered (not including hmax) */
9923 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9924 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9925 SCIP_CONS* cons, /**< underlying constraint, or NULL */
9926 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9927 int* nfixedvars, /**< pointer to store the number of fixed variables */
9928 int* nchgsides, /**< pointer to store the number of changed sides */
9929 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9930 )
9931{
9932 SCIP_Real* downimpllbs;
9933 SCIP_Real* downimplubs;
9934 SCIP_Real* downproplbs;
9935 SCIP_Real* downpropubs;
9936 SCIP_Real* upimpllbs;
9937 SCIP_Real* upimplubs;
9938 SCIP_Real* upproplbs;
9939 SCIP_Real* uppropubs;
9940
9941 int firstminect;
9942 int secondminect;
9943 int v;
9944
9945 /* get temporary memory for storing probing results needed for step (4) and (5) */
9954
9955 assert(scip != NULL);
9956 assert(nvars > 1);
9957 assert(cons != NULL);
9958
9959 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9960
9963
9964 /* compute the two smallest earlier completion times; which are needed for step (5) */
9965 for( v = 0; v < nvars; ++v )
9966 {
9967 int ect;
9968
9969 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9970
9971 if( ect < firstminect )
9972 {
9974 firstminect = ect;
9975 }
9976 else if( ect < secondminect )
9977 secondminect = ect;
9978 }
9979
9980 /* loop over all jobs and check if one of the 5 reductions can be applied */
9981 for( v = 0; v < nvars; ++v )
9982 {
9983 SCIP_VAR* var;
9984 int duration;
9985
9986 int alternativelb;
9987 int minect;
9988 int est;
9989 int ect;
9990 int lst;
9991 int lct;
9992
9993 var = vars[v];
9994 assert(var != NULL);
9995
9996 duration = durations[v];
9997 assert(duration > 0);
9998
9999 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10000 * time (lct)
10001 */
10003 ect = est + duration;
10005 lct = lst + duration;
10006
10007 /* compute the earliest completion time of all remaining jobs */
10008 if( ect == firstminect )
10010 else
10012
10013 /* compute potential alternative lower bound (step (4) and (5)) */
10014 alternativelb = MAX(hmin+1, minect);
10016
10017 if( lct <= hmin )
10018 {
10019 /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
10020 * cumulative condition
10021 */
10022 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10024
10025 /* mark variable to be irrelevant */
10026 irrelevants[v] = TRUE;
10027
10028 /* for the statistic we count the number of jobs which are irrelevant */
10030 }
10031 else if( lst <= hmin && SCIPconsIsChecked(cons) )
10032 {
10033 /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
10034 * so the down lock can be omitted
10035 */
10036
10037 assert(downlocks != NULL);
10038 assert(uplocks != NULL);
10039
10040 if( !uplocks[v] )
10041 {
10042 /* the variables has no up lock and we can also remove the down lock;
10043 * => lst <= hmin and ect >= hmax
10044 * => remove job and reduce capacity by the demand of that job
10045 *
10046 * We mark the job to be deletable. The removement together with the capacity reducion is done later
10047 */
10048
10049 SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10050 SCIPvarGetName(var), ect - duration, lst, duration);
10051
10052 /* mark variable to be irrelevant */
10053 irrelevants[v] = TRUE;
10054
10055 /* for the statistic we count the number of jobs which always run during the effective horizon */
10057 }
10058
10059 if( downlocks[v] )
10060 {
10061 SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10063
10065 downlocks[v] = FALSE;
10066 (*nchgsides)++;
10067
10068 /* for the statistic we count the number of removed locks */
10070 }
10071 }
10072 else if( ect <= hmin )
10073 {
10074 /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10075 * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10076 * removed form the cumulative condition after it was fixed to its earliest start time
10077 */
10078
10079 /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10080 * bound;
10081 */
10082 if( downlocks != NULL && SCIPconsIsChecked(cons) )
10083 {
10084 /* fix integer start time variable if possible to it lower bound */
10085 SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10086 }
10087
10089 {
10090 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10091 SCIPvarGetName(var), ect - duration, lst, duration);
10092
10093 /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10094 assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10095
10096 /* mark variable to be irrelevant */
10097 irrelevants[v] = TRUE;
10098
10099 /* for the statistic we count the number of jobs which are dual fixed */
10101 }
10102 }
10103 else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10104 {
10105 assert(downlocks != NULL);
10106
10107 /* check step (4) and (5) */
10108
10109 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10110 * is in favor of rounding the variable down
10111 */
10112 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10113 {
10114 SCIP_Bool roundable;
10115
10117
10118 if( roundable )
10119 {
10120 if( alternativelb > lst )
10121 {
10122 SCIP_Bool infeasible;
10123 SCIP_Bool fixed;
10124
10125 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10126 assert(!infeasible);
10127 assert(fixed);
10128
10129 (*nfixedvars)++;
10130
10131 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10132 * constraints
10133 */
10135 }
10136 else
10137 {
10138 SCIP_Bool success;
10139
10140 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10141 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10142 * infeasible we can apply the dual reduction; otherwise we do nothing
10143 */
10144 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10146 nfixedvars, &success, cutoff) );
10147
10148 if( success )
10149 {
10151 }
10152 }
10153 }
10154 }
10155 }
10156
10157 SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10159 }
10160
10161 /* free temporary memory */
10170
10171 return SCIP_OKAY;
10172}
10173
10174/** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10175 *
10176 * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10177 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10178 *
10179 * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10180 * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10181 * up-lock of the corresponding start time variable can be removed.
10182 *
10183 * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10184 * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10185 * positive, than the job can be dual fixed to its latest start time (lst).
10186 *
10187 * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10188 * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10189 * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10190 * of the corresponding job).
10191
10192 * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10193 * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10194 * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10195 * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10196 *
10197 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10198 * the cumulative condition; The deletion has to be done later.
10199 */
10200static
10202 SCIP* scip, /**< SCIP data structure */
10203 int nvars, /**< number of start time variables (activities) */
10204 SCIP_VAR** vars, /**< array of start time variables */
10205 int* durations, /**< array of durations */
10206 int hmin, /**< left bound of time axis to be considered (including hmin) */
10207 int hmax, /**< right bound of time axis to be considered (not including hmax) */
10208 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10209 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10210 SCIP_CONS* cons, /**< underlying constraint, or NULL */
10211 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10212 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10213 int* nchgsides, /**< pointer to store the number of changed sides */
10214 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10215 )
10216{
10217 SCIP_Real* downimpllbs;
10218 SCIP_Real* downimplubs;
10219 SCIP_Real* downproplbs;
10220 SCIP_Real* downpropubs;
10221 SCIP_Real* upimpllbs;
10222 SCIP_Real* upimplubs;
10223 SCIP_Real* upproplbs;
10224 SCIP_Real* uppropubs;
10225
10226 int firstmaxlst;
10227 int secondmaxlst;
10228 int v;
10229
10230 /* get temporary memory for storing probing results needed for step (4) and (5) */
10239
10240 assert(scip != NULL);
10241 assert(nvars > 1);
10242 assert(cons != NULL);
10243
10244 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10245
10248
10249 /* compute the two largest latest start times; which are needed for step (5) */
10250 for( v = 0; v < nvars; ++v )
10251 {
10252 int lst;
10253
10255
10256 if( lst > firstmaxlst )
10257 {
10259 firstmaxlst = lst;
10260 }
10261 else if( lst > secondmaxlst )
10262 secondmaxlst = lst;
10263 }
10264
10265 /* loop over all jobs and check if one of the 5 reductions can be applied */
10266 for( v = 0; v < nvars; ++v )
10267 {
10268 SCIP_VAR* var;
10269 int duration;
10270
10271 int alternativeub;
10272 int maxlst;
10273 int est;
10274 int ect;
10275 int lst;
10276
10277 var = vars[v];
10278 assert(var != NULL);
10279
10280 duration = durations[v];
10281 assert(duration > 0);
10282
10283 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10284 * time (lct)
10285 */
10287 ect = est + duration;
10289
10290 /* compute the latest start time of all remaining jobs */
10291 if( lst == firstmaxlst )
10293 else
10295
10296 /* compute potential alternative upper bound (step (4) and (5)) */
10297 alternativeub = MIN(hmax - 1, maxlst) - duration;
10299
10300 if( est >= hmax )
10301 {
10302 /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10303 * cumulative condition
10304 */
10305 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10307
10308 /* mark variable to be irrelevant */
10309 irrelevants[v] = TRUE;
10310
10311 /* for the statistic we count the number of jobs which are irrelevant */
10313 }
10314 else if( ect >= hmax && SCIPconsIsChecked(cons) )
10315 {
10316 assert(downlocks != NULL);
10317 assert(uplocks != NULL);
10318
10319 /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10320 * so the up lock can be omitted
10321 */
10322
10323 if( !downlocks[v] )
10324 {
10325 /* the variables has no down lock and we can also remove the up lock;
10326 * => lst <= hmin and ect >= hmax
10327 * => remove job and reduce capacity by the demand of that job
10328 */
10329 SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10330 SCIPvarGetName(var), est, lst, duration);
10331
10332 /* mark variable to be irrelevant */
10333 irrelevants[v] = TRUE;
10334
10335 /* for the statistic we count the number of jobs which always run during the effective horizon */
10337 }
10338
10339 if( uplocks[v] )
10340 {
10341 SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10343
10345 uplocks[v] = FALSE;
10346 (*nchgsides)++;
10347
10348 /* for the statistic we count the number of removed locks */
10350 }
10351 }
10352 else if( lst >= hmax )
10353 {
10354 /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10355 * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10356 * removed form the cumulative condition after it was fixed to its latest start time
10357 */
10358
10359 /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10360 * bound
10361 */
10362 if( uplocks != NULL && SCIPconsIsChecked(cons) )
10363 {
10364 /* fix integer start time variable if possible to its upper bound */
10365 SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10366 }
10367
10369 {
10370 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10371 SCIPvarGetName(var), est, lst, duration);
10372
10373 /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10375
10376 /* mark variable to be irrelevant */
10377 irrelevants[v] = TRUE;
10378
10379 /* for the statistic we count the number of jobs which are dual fixed */
10381 }
10382 }
10384 {
10385 assert(uplocks != NULL);
10386
10387 /* check step (4) and (5) */
10388
10389 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10390 * is in favor of rounding the variable down
10391 */
10392 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10393 {
10394 SCIP_Bool roundable;
10395
10397
10398 if( roundable )
10399 {
10400 if( alternativeub < est )
10401 {
10402 SCIP_Bool infeasible;
10403 SCIP_Bool fixed;
10404
10405 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10406 assert(!infeasible);
10407 assert(fixed);
10408
10409 (*nfixedvars)++;
10410
10411 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10412 * constraints
10413 */
10415 }
10416 else
10417 {
10418 SCIP_Bool success;
10419
10420 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10421 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10422 * in infeasible we can apply the dual reduction; otherwise we do nothing
10423 */
10424 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10426 nfixedvars, &success, cutoff) );
10427
10428 if( success )
10429 {
10431 }
10432 }
10433 }
10434 }
10435 }
10436 }
10437
10438 /* free temporary memory */
10447
10448 return SCIP_OKAY;
10449}
10450
10451/** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10452static
10454 SCIP* scip, /**< SCIP data structure */
10455 SCIP_CONS* cons, /**< cumulative constraint */
10456 int* nfixedvars, /**< pointer to store the number of fixed variables */
10457 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10458 int* nchgsides, /**< pointer to store the number of changed sides */
10459 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10460 )
10461{
10462 SCIP_CONSDATA* consdata;
10463 SCIP_Bool* irrelevants;
10464 int nvars;
10465 int v;
10466
10467 assert(scip != NULL);
10468 assert(cons != NULL);
10469 assert(!(*cutoff));
10470
10471 consdata = SCIPconsGetData(cons);
10472 assert(consdata != NULL);
10473
10474 nvars = consdata->nvars;
10475
10476 if( nvars <= 1 )
10477 return SCIP_OKAY;
10478
10481
10482 /* presolve constraint form the earlier start time point of view */
10483 SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10484 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10485 irrelevants, nfixedvars, nchgsides, cutoff) );
10486
10487 /* presolve constraint form the latest completion time point of view */
10488 SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10489 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10490 irrelevants, nfixedvars, nchgsides, cutoff) );
10491
10492 /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10493 * order to ensure a correct behaviour
10494 */
10495 for( v = nvars-1; v >= 0; --v )
10496 {
10497 if( irrelevants[v] )
10498 {
10499 SCIP_VAR* var;
10500 int ect;
10501 int lst;
10502
10503 var = consdata->vars[v];
10504 assert(var != NULL);
10505
10506 ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10508
10509 /* check if the jobs runs completely during the effective horizon */
10510 if( lst <= consdata->hmin && ect >= consdata->hmax )
10511 {
10512 if( consdata->capacity < consdata->demands[v] )
10513 {
10514 *cutoff = TRUE;
10515 break;
10516 }
10517
10518 consdata->capacity -= consdata->demands[v];
10519 consdata->varbounds = FALSE;
10520 }
10521
10522 SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10523 (*nchgcoefs)++;
10524 }
10525 }
10526
10528
10529 return SCIP_OKAY;
10530}
10531
10532/** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10533static
10535 SCIP* scip, /**< SCIP data structure */
10536 SCIP_CONSDATA* consdata, /**< constraint data */
10537 int* startindices, /**< permutation with rspect to the start times */
10538 int curtime, /**< current point in time */
10539 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10540 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10541 SCIP_Longint** demands, /**< pointer to array storing the demands */
10542 int* ndemands /**< pointer to store the number of different demands */
10543 )
10544{
10545 int startindex;
10546 int ncountedvars;
10547
10548 assert(demands != NULL);
10549 assert(ndemands != NULL);
10550
10551 ncountedvars = 0;
10552 startindex = nstarted - 1;
10553
10554 *ndemands = 0;
10555
10556 /* search for the (nstarted - nfinished) jobs which are active at curtime */
10557 while( nstarted - nfinished > ncountedvars )
10558 {
10559 SCIP_VAR* var;
10560 int endtime;
10561 int varidx;
10562
10563 /* collect job information */
10564 varidx = startindices[startindex];
10566
10567 var = consdata->vars[varidx];
10568 assert(var != NULL);
10569
10570 endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10571
10572 /* check the end time of this job is larger than the curtime; in this case the job is still running */
10573 if( endtime > curtime )
10574 {
10575 if( consdata->demands[varidx] < consdata->capacity )
10576 {
10577 (*demands)[*ndemands] = consdata->demands[varidx];
10578 (*ndemands)++;
10579 }
10580 ncountedvars++;
10581 }
10582
10583 startindex--;
10584 }
10585}
10586
10587/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10588 * constraint
10589 */
10590static
10592 SCIP* scip, /**< SCIP data structure */
10593 SCIP_CONS* cons, /**< constraint to be checked */
10594 int* startindices, /**< permutation with rspect to the start times */
10595 int curtime, /**< current point in time */
10596 int nstarted, /**< number of jobs that start before the curtime or at curtime */
10597 int nfinished, /**< number of jobs that finished before curtime or at curtime */
10598 int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10599 )
10600{
10601 SCIP_CONSDATA* consdata;
10602 SCIP_Longint* demands;
10603 SCIP_Real* profits;
10604 int* items;
10605 int ndemands;
10606 SCIP_Bool success;
10607 SCIP_Real solval;
10608 int j;
10610
10611 consdata = SCIPconsGetData(cons);
10612 assert(consdata != NULL);
10613 assert(consdata->nvars > 0);
10614 assert(consdata->capacity > 0);
10615
10616 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10617 ndemands = 0;
10618
10619 /* get demand array to initialize knapsack problem */
10620 collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10621
10622 /* create array for profits */
10625 for( j = 0; j < ndemands; ++j )
10626 {
10627 profits[j] = (SCIP_Real) demands[j];
10628 items[j] = j;/* this is only a dummy value*/
10629 }
10630
10631 /* solve knapsack problem and get maximum capacity usage <= capacity */
10632 SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10633 items, NULL, NULL, NULL, NULL, &solval, &success) );
10634
10635 assert(SCIPisFeasIntegral(scip, solval));
10636
10637 /* store result */
10639
10642 SCIPfreeBufferArray(scip, &demands);
10643
10644 return SCIP_OKAY;
10645}
10646
10647/** try to tighten the capacity
10648 * -- using DP for knapsack, we find the maximum possible capacity usage
10649 * -- neglects hmin and hmax, such that it is also able to check solutions globally
10650 */
10651static
10653 SCIP* scip, /**< SCIP data structure */
10654 SCIP_CONS* cons, /**< cumulative constraint */
10655 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10656 int* nchgsides /**< pointer to store the number of changed sides */
10657 )
10658{
10659 SCIP_CONSDATA* consdata;
10660 int* starttimes; /* stores when each job is starting */
10661 int* endtimes; /* stores when each job ends */
10662 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10663 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10664
10665 int nvars; /* number of activities for this constraint */
10666 int freecapacity; /* remaining capacity */
10667 int curtime; /* point in time which we are just checking */
10668 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10669
10670 int bestcapacity;
10671
10672 int j;
10673
10674 assert(scip != NULL);
10675 assert(cons != NULL);
10676 assert(nchgsides != NULL);
10677
10678 consdata = SCIPconsGetData(cons);
10679 assert(consdata != NULL);
10680
10681 nvars = consdata->nvars;
10682
10683 /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10684 if( nvars <= 1 || consdata->capacity <= 1 )
10685 return SCIP_OKAY;
10686
10687 assert(consdata->vars != NULL);
10688
10689 SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10690 SCIPconsGetName(cons), consdata->capacity);
10691
10694 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10696
10697 /* create event point arrays */
10698 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10699 starttimes, endtimes, startindices, endindices, FALSE);
10700
10701 bestcapacity = 1;
10702 endindex = 0;
10703 freecapacity = consdata->capacity;
10704
10705 /* check each startpoint of a job whether the capacity is kept or not */
10706 for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10707 {
10708 curtime = starttimes[j];
10709 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10710
10711 /* remove the capacity requirments for all job which start at the curtime */
10712 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10713
10714 /* add the capacity requirments for all job which end at the curtime */
10716
10718 assert(endindex <= nvars);
10719
10720 /* endindex - points to the next job which will finish */
10721 /* j - points to the last job that has been released */
10722
10723 /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10724 if( freecapacity < 0 )
10725 {
10726 int newcapacity;
10727
10728 newcapacity = 1;
10729
10730 /* get best possible upper bound on capacity usage */
10731 SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10732
10733 /* update bestcapacity */
10735 SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10736 }
10737
10738 /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10739 if( freecapacity > 0 && freecapacity != consdata->capacity )
10740 {
10741 bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10742 SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10743 }
10744
10745 /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10746 if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10747 {
10748 /* if demands[startindices[j]] == cap then exactly that job is running */
10749 SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10750 bestcapacity = consdata->capacity;
10751 break;
10752 }
10753 } /*lint --e{850}*/
10754
10755 /* free all buffer arrays */
10757 SCIPfreeBufferArray(scip, &startindices);
10760
10761 /* check whether capacity can be tightened and whether demands need to be adjusted */
10762 if( bestcapacity < consdata->capacity )
10763 {
10764 SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10765
10766 SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10767 SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10768
10769 for( j = 0; j < nvars; ++j )
10770 {
10771 if( consdata->demands[j] == consdata->capacity )
10772 {
10773 consdata->demands[j] = bestcapacity;
10774 (*nchgcoefs)++;
10775 }
10776 }
10777
10778 consdata->capacity = bestcapacity;
10779 (*nchgsides)++;
10780
10781 SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10782
10783 consdata->varbounds = FALSE;
10784 }
10785
10786 return SCIP_OKAY;
10787}
10788
10789/** tries to change coefficients:
10790 * demand_j < cap && all other parallel jobs in conflict
10791 * ==> set demand_j := cap
10792 */
10793static
10795 SCIP* scip, /**< SCIP data structure */
10796 SCIP_CONS* cons, /**< cumulative constraint */
10797 int* nchgcoefs /**< pointer to count total number of changed coefficients */
10798 )
10799{
10800 SCIP_CONSDATA* consdata;
10801 int nvars;
10802 int j;
10803 int oldnchgcoefs;
10804 int mindemand;
10805
10806 assert(scip != NULL);
10807 assert(cons != NULL);
10808 assert(nchgcoefs != NULL);
10809
10810 /* get constraint data for some parameter testings only! */
10811 consdata = SCIPconsGetData(cons);
10812 assert(consdata != NULL);
10813
10814 nvars = consdata->nvars;
10815 oldnchgcoefs = *nchgcoefs;
10816
10817 if( nvars <= 0 )
10818 return SCIP_OKAY;
10819
10820 /* PRE1:
10821 * check all jobs j whether: r_j + r_min > capacity holds
10822 * if so: adjust r_j to capacity
10823 */
10824 mindemand = consdata->demands[0];
10825 for( j = 0; j < nvars; ++j )
10826 {
10827 mindemand = MIN(mindemand, consdata->demands[j]);
10828 }
10829
10830 /*check each job */
10831 for( j = 0; j < nvars; ++j )
10832 {
10833 if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10834 {
10835 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10836 consdata->demands[j], consdata->capacity);
10837 consdata->demands[j] = consdata->capacity;
10838 (*nchgcoefs)++;
10839 }
10840 }
10841
10842 /* PRE2:
10843 * check for each job (with d_j < cap)
10844 * whether it is disjunctive to all others over the time horizon
10845 */
10846 for( j = 0; j < nvars; ++j )
10847 {
10848 SCIP_Bool chgcoef;
10849 int est_j;
10850 int lct_j;
10851 int i;
10852
10853 assert(consdata->demands[j] <= consdata->capacity);
10854
10855 if( consdata->demands[j] == consdata->capacity )
10856 continue;
10857
10858 chgcoef = TRUE;
10859
10860 est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10861 lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10862
10863 for( i = 0; i < nvars; ++i )
10864 {
10865 int est_i;
10866 int lct_i;
10867
10868 if( i == j )
10869 continue;
10870
10871 est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10872 lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10873
10874 if( est_i >= lct_j || est_j >= lct_i )
10875 continue;
10876
10877 if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10878 {
10879 chgcoef = FALSE;
10880 break;
10881 }
10882 }
10883
10884 if( chgcoef )
10885 {
10886 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10887 consdata->demands[j], consdata->capacity);
10888 consdata->demands[j] = consdata->capacity;
10889 (*nchgcoefs)++;
10890 }
10891 }
10892
10893 if( (*nchgcoefs) > oldnchgcoefs )
10894 {
10895 SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10896 (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10897 }
10898
10899 return SCIP_OKAY;
10900}
10901
10902#if 0
10903/** try to reformulate constraint by replacing certain jobs */
10904static
10906 SCIP* scip, /**< SCIP data structure */
10907 SCIP_CONS* cons, /**< cumulative constraint */
10908 int* naggrvars /**< pointer to store the number of aggregated variables */
10909 )
10910{
10911 SCIP_CONSDATA* consdata;
10912 int hmin;
10913 int hmax;
10914 int nvars;
10915 int v;
10916
10917 consdata = SCIPconsGetData(cons);
10918 assert(cons != NULL);
10919
10920 nvars = consdata->nvars;
10921 assert(nvars > 1);
10922
10923 hmin = consdata->hmin;
10924 hmax = consdata->hmax;
10925 assert(hmin < hmax);
10926
10927 for( v = 0; v < nvars; ++v )
10928 {
10929 SCIP_VAR* var;
10930 int duration;
10931 int est;
10932 int ect;
10933 int lst;
10934 int lct;
10935
10936 var = consdata->vars[v];
10937 assert(var != NULL);
10938
10939 duration = consdata->durations[v];
10940
10942 ect = est + duration;
10944 lct = lst + duration;
10945
10946 /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10947 assert(lst > hmin || ect < hmax);
10948
10949 if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10950 {
10952 char name[SCIP_MAXSTRLEN];
10953 SCIP_Bool infeasible;
10954 SCIP_Bool redundant;
10955 SCIP_Bool aggregated;
10956 int shift;
10957
10958 shift = est - (hmin - lct + MIN(hmin, ect));
10959 assert(shift > 0);
10960 lst = hmin;
10961 duration = hmin - lct;
10962
10963 SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10965
10966 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10967 SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10970 SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10971
10972 assert(!infeasible);
10973 assert(!redundant);
10975
10976 /* replace variable */
10977 consdata->durations[v] = duration;
10978 consdata->vars[v] = aggrvar;
10979
10980 /* remove and add locks */
10981 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10982 SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10983
10985
10986 (*naggrvars)++;
10987 }
10988 }
10989
10990 return SCIP_OKAY;
10991}
10992#endif
10993
10994/** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10995static
10997 SCIP* scip, /**< SCIP data structure */
10998 SCIP_CONS* cons, /**< cumulative constraint */
10999 int* naddconss /**< pointer to store the number of added constraints */
11000 )
11001{
11002 SCIP_CONSDATA* consdata;
11003 SCIP_VAR** vars;
11004 int* durations;
11005 int* demands;
11006 int capacity;
11007 int halfcapacity;
11008 int mindemand;
11009 int nvars;
11010 int v;
11011
11012 consdata = SCIPconsGetData(cons);
11013 assert(consdata != NULL);
11014
11015 capacity = consdata->capacity;
11016
11017 if( capacity == 1 )
11018 return SCIP_OKAY;
11019
11020 SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
11021 SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
11022 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
11023
11024 halfcapacity = capacity / 2;
11025 mindemand = consdata->capacity;
11026 nvars = 0;
11027
11028 /* collect all jobs with demand larger than half of the capacity */
11029 for( v = 0; v < consdata->nvars; ++v )
11030 {
11031 if( consdata->demands[v] > halfcapacity )
11032 {
11033 vars[nvars] = consdata->vars[v];
11034 demands[nvars] = 1;
11035 durations[nvars] = consdata->durations[v];
11036 nvars++;
11037
11038 mindemand = MIN(mindemand, consdata->demands[v]);
11039 }
11040 }
11041
11042 if( nvars > 0 )
11043 {
11044 /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11045 * job is still to large to be scheduled in parallel
11046 */
11047 for( v = 0; v < consdata->nvars; ++v )
11048 {
11049 if( consdata->demands[v] > halfcapacity )
11050 continue;
11051
11052 if( mindemand + consdata->demands[v] > capacity )
11053 {
11054 demands[nvars] = 1;
11055 durations[nvars] = consdata->durations[v];
11056 vars[nvars] = consdata->vars[v];
11057 nvars++;
11058
11059 /* @todo create one cumulative constraint and look for another small demand */
11060 break;
11061 }
11062 }
11063
11064 /* creates cumulative constraint and adds it to problem */
11065 SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11067 (*naddconss)++;
11068 }
11069
11070 SCIPfreeBufferArray(scip, &demands);
11071 SCIPfreeBufferArray(scip, &durations);
11073
11074 return SCIP_OKAY;
11075}
11076
11077/** presolve given constraint */
11078static
11080 SCIP* scip, /**< SCIP data structure */
11081 SCIP_CONS* cons, /**< cumulative constraint */
11082 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11083 SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11084 int* nfixedvars, /**< pointer to store the number of fixed variables */
11085#if 0
11086 int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11087#endif
11088 int* nchgbds, /**< pointer to store the number of changed bounds */
11089 int* ndelconss, /**< pointer to store the number of deleted constraints */
11090 int* naddconss, /**< pointer to store the number of added constraints */
11091 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11092 int* nchgsides, /**< pointer to store the number of changed sides */
11093 SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11094 SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11095 )
11096{
11097 assert(!SCIPconsIsDeleted(cons));
11098
11099 /* only perform dual reductions on model constraints */
11100 if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11101 {
11102 /* computes the effective horizon and checks if the constraint can be decomposed */
11103 SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11104
11105 if( SCIPconsIsDeleted(cons) )
11106 return SCIP_OKAY;
11107
11108 /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11109 * fixings (dual reductions)
11110 */
11111 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11112 {
11113 SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11114
11115 if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11116 return SCIP_OKAY;
11117 }
11118
11119 SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11120
11121 if( *cutoff || SCIPconsIsDeleted(cons) )
11122 return SCIP_OKAY;
11123 }
11124
11125 /* remove jobs which have a demand larger than the capacity */
11126 SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11127 assert((*cutoff) || checkDemands(scip, cons));
11128
11129 if( *cutoff )
11130 return SCIP_OKAY;
11131
11132 if( conshdlrdata->normalize )
11133 {
11134 /* divide demands by their greatest common divisor */
11135 normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11136 }
11137
11138 /* delete constraint with one job */
11139 SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11140
11141 if( *cutoff || SCIPconsIsDeleted(cons) )
11142 return SCIP_OKAY;
11143
11144 if( conshdlrdata->coeftightening )
11145 {
11146 /* try to tighten the capacity */
11147 SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11148
11149 /* try to tighten the coefficients */
11150 SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11151 }
11152
11153 assert(checkDemands(scip, cons) || *cutoff);
11154
11155#if 0
11156 SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11157#endif
11158
11159 return SCIP_OKAY;
11160}
11161
11162/**@name TClique Graph callbacks
11163 *
11164 * @{
11165 */
11166
11167/** tclique graph data */
11168struct TCLIQUE_Graph
11169{
11170 SCIP_VAR** vars; /**< start time variables each of them is a node */
11171 SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11172 SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11173 SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11174 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11175 int* ninarcs; /**< number if in arcs for the precedence graph */
11176 int* noutarcs; /**< number if out arcs for the precedence graph */
11177 int* durations; /**< for each node the duration of the corresponding job */
11178 int nnodes; /**< number of nodes */
11179 int size; /**< size of the array */
11180};
11181
11182/** gets number of nodes in the graph */
11183static
11185{
11186 assert(tcliquegraph != NULL);
11187
11188 return tcliquegraph->nnodes;
11189}
11190
11191/** gets weight of nodes in the graph */
11192static
11194{
11195 assert(tcliquegraph != NULL);
11196
11197 return tcliquegraph->weights;
11198}
11199
11200/** returns, whether the edge (node1, node2) is in the graph */
11201static
11203{
11204 assert(tcliquegraph != NULL);
11205 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11206 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11207
11208 /* check if an arc exits in the precedence graph */
11209 if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11210 return TRUE;
11211
11212 /* check if an edge exits in the non-overlapping graph */
11213 if( tcliquegraph->demandmatrix[node1][node2] )
11214 return TRUE;
11215
11216 return FALSE;
11217}
11218
11219/** selects all nodes from a given set of nodes which are adjacent to a given node
11220 * and returns the number of selected nodes
11221 */
11222static
11224{
11225 int nadjnodes;
11226 int i;
11227
11228 assert(tcliquegraph != NULL);
11229 assert(0 <= node && node < tcliquegraph->nnodes);
11230 assert(nnodes == 0 || nodes != NULL);
11231 assert(adjnodes != NULL);
11232
11233 nadjnodes = 0;
11234
11235 for( i = 0; i < nnodes; i++ )
11236 {
11237 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11238 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11239 assert(i == 0 || nodes[i-1] < nodes[i]);
11240
11241 /* check if an edge exists */
11242 if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11243 {
11244 /* current node is adjacent to given node */
11245 adjnodes[nadjnodes] = nodes[i];
11246 nadjnodes++;
11247 }
11248 }
11249
11250 return nadjnodes;
11251}
11252
11253/** generates cuts using a clique found by algorithm for maximum weight clique
11254 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11255 */
11256static
11258{ /*lint --e{715}*/
11259 SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11260}
11261
11262/** print the tclique graph */
11263#if 0
11264static
11265void tcliquePrint(
11266 SCIP* scip, /**< SCIP data structure */
11267 TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11268 )
11269{
11270 int nnodes;
11271 int i;
11272 int j;
11273
11274 nnodes = tcliquegraph->nnodes;
11275
11276 for( i = 0; i < nnodes; ++i )
11277 {
11278 for( j = 0; j < nnodes; ++j )
11279 {
11280 SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11281 }
11282 SCIPinfoMessage(scip, NULL, "\n");
11283 }
11284}
11285#endif
11286
11287/** @} */
11288
11289/** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11290 * job corresponding to variable bound variable (vlbvar)
11291 *
11292 * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11293 */
11294static
11296 SCIP* scip, /**< SCIP data structure */
11297 SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11298 SCIP_Real vlbcoef, /**< variable bound coefficient */
11299 SCIP_Real vlbconst, /**< variable bound constant */
11300 int duration /**< duration of the variable bound variable */
11301 )
11302{
11303 if( SCIPisEQ(scip, vlbcoef, 1.0) )
11304 {
11305 if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11306 {
11307 /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11308 return TRUE;
11309 }
11310 }
11311 else
11312 {
11313 SCIP_Real bound;
11314
11315 bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11316
11317 if( SCIPisLT(scip, vlbcoef, 1.0) )
11318 {
11319 SCIP_Real ub;
11320
11322
11323 /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11324 if( SCIPisLE(scip, ub, bound) )
11325 return TRUE;
11326 }
11327 else
11328 {
11329 SCIP_Real lb;
11330
11331 assert(SCIPisGT(scip, vlbcoef, 1.0));
11332
11334
11335 /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11336 if( SCIPisGE(scip, lb, bound) )
11337 return TRUE;
11338 }
11339 }
11340
11341 return FALSE;
11342}
11343
11344/** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11345 * job corresponding to variable which is bounded (var)
11346 *
11347 * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11348 */
11349static
11351 SCIP* scip, /**< SCIP data structure */
11352 SCIP_VAR* var, /**< variable which is bound from above */
11353 SCIP_Real vubcoef, /**< variable bound coefficient */
11354 SCIP_Real vubconst, /**< variable bound constant */
11355 int duration /**< duration of the variable which is bounded from above */
11356 )
11357{
11358 SCIP_Real vlbcoef;
11359 SCIP_Real vlbconst;
11360
11361 /* convert the variable upper bound into an variable lower bound */
11362 vlbcoef = 1.0 / vubcoef;
11364
11366}
11367
11368/** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11369 * others an index larger than the number if active variables
11370 */
11371static
11373 SCIP* scip, /**< SCIP data structure */
11374 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11375 SCIP_VAR* var, /**< variable for which we want the index */
11376 int* idx /**< pointer to store the index */
11377 )
11378{
11379 (*idx) = SCIPvarGetProbindex(var);
11380
11381 if( (*idx) == -1 )
11382 {
11383 if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11384 {
11385 (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11386 }
11387 else
11388 {
11389 int pos;
11390 int v;
11391
11392 /**@todo we might want to add the aggregation path to graph */
11393
11394 /* check if we have to realloc memory */
11395 if( tcliquegraph->size == tcliquegraph->nnodes )
11396 {
11397 int size;
11398
11399 size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11400 tcliquegraph->size = size;
11401
11402 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11403 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11404 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11405 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11406 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11407
11408 for( v = 0; v < tcliquegraph->nnodes; ++v )
11409 {
11410 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11411 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11412 }
11413 }
11414 assert(tcliquegraph->nnodes < tcliquegraph->size);
11415
11416 pos = tcliquegraph->nnodes;
11417 assert(pos >= 0);
11418
11419 tcliquegraph->durations[pos] = 0;
11420 tcliquegraph->weights[pos] = 0;
11421 tcliquegraph->vars[pos] = var;
11422
11423 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11424 BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11425
11426 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11427 BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11428
11429 SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11430
11431 tcliquegraph->nnodes++;
11432
11433 for( v = 0; v < tcliquegraph->nnodes; ++v )
11434 {
11435 tcliquegraph->precedencematrix[v][pos] = 0;
11436 tcliquegraph->demandmatrix[v][pos] = 0;
11437 }
11438
11439 (*idx) = tcliquegraph->nnodes;
11440 }
11441 }
11442 else
11443 {
11444 assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11445 }
11446
11447 assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11448
11449 return SCIP_OKAY;
11450}
11451
11452/** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11453 *
11454 * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11455 * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11456 *
11457 * (i) b = 1 and c >= d
11458 * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11459 * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11460 *
11461 */
11462static
11464 SCIP* scip, /**< SCIP data structure */
11465 TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11466 )
11467{
11468 SCIP_VAR** vars;
11469 int nvars;
11470 int v;
11471
11474
11475 /* try to project each arc of the variable bound graph to precedence condition */
11476 for( v = 0; v < nvars; ++v )
11477 {
11478 SCIP_VAR** vbdvars;
11479 SCIP_VAR* var;
11480 SCIP_Real* vbdcoefs;
11481 SCIP_Real* vbdconsts;
11482 int nvbdvars;
11483 int idx1;
11484 int b;
11485
11486 var = vars[v];
11487 assert(var != NULL);
11488
11489 SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11490 assert(idx1 >= 0);
11491
11492 if( tcliquegraph->durations[idx1] == 0 )
11493 continue;
11494
11499
11500 for( b = 0; b < nvbdvars; ++b )
11501 {
11502 int idx2;
11503
11504 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11505 assert(idx2 >= 0);
11506
11507 if( tcliquegraph->durations[idx2] == 0 )
11508 continue;
11509
11510 if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11511 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11512 }
11513
11518
11519 for( b = 0; b < nvbdvars; ++b )
11520 {
11521 int idx2;
11522
11523 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11524 assert(idx2 >= 0);
11525
11526 if( tcliquegraph->durations[idx2] == 0 )
11527 continue;
11528
11529 if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11530 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11531 }
11532
11533 for( b = v+1; b < nvars; ++b )
11534 {
11535 int idx2;
11536
11537 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11538 assert(idx2 >= 0);
11539
11540 if( tcliquegraph->durations[idx2] == 0 )
11541 continue;
11542
11543 /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11544 if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11545 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11546
11547 /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11548 if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11549 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11550 }
11551 }
11552
11553 return SCIP_OKAY;
11554}
11555
11556/** compute the transitive closer of the given graph and the number of in and out arcs */
11557static
11559 SCIP_Bool** adjmatrix, /**< adjacent matrix */
11560 int* ninarcs, /**< array to store the number of in arcs */
11561 int* noutarcs, /**< array to store the number of out arcs */
11562 int nnodes /**< number if nodes */
11563 )
11564{
11565 int i;
11566 int j;
11567 int k;
11568
11569 for( i = 0; i < nnodes; ++i )
11570 {
11571 for( j = 0; j < nnodes; ++j )
11572 {
11573 if( adjmatrix[i][j] )
11574 {
11575 ninarcs[j]++;
11576 noutarcs[i]++;
11577
11578 for( k = 0; k < nnodes; ++k )
11579 {
11580 if( adjmatrix[j][k] )
11581 adjmatrix[i][k] = TRUE;
11582 }
11583 }
11584 }
11585 }
11586}
11587
11588/** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11589static
11591 SCIP* scip, /**< SCIP data structure */
11592 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11593 SCIP_CONS** conss, /**< array of cumulative constraints */
11594 int nconss /**< number of cumulative constraints */
11595 )
11596{
11597 int c;
11598
11599 /* use the cumulative constraints to initialize the none overlapping graph */
11600 for( c = 0; c < nconss; ++c )
11601 {
11602 SCIP_CONSDATA* consdata;
11603 SCIP_VAR** vars;
11604 int* demands;
11605 int capacity;
11606 int nvars;
11607 int i;
11608
11609 consdata = SCIPconsGetData(conss[c]);
11610 assert(consdata != NULL);
11611
11612 vars = consdata->vars;
11613 demands = consdata->demands;
11614
11615 nvars = consdata->nvars;
11616 capacity = consdata->capacity;
11617
11618 SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11619
11620 /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11621 for( i = 0; i < nvars; ++i )
11622 {
11623 int idx1;
11624 int j;
11625
11626 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11627 assert(idx1 >= 0);
11628
11629 if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11630 continue;
11631
11632 for( j = i+1; j < nvars; ++j )
11633 {
11634 assert(consdata->durations[j] > 0);
11635
11636 if( demands[i] + demands[j] > capacity )
11637 {
11638 int idx2;
11639 int est1;
11640 int est2;
11641 int lct1;
11642 int lct2;
11643
11644 /* check if the effective horizon is large enough */
11647
11648 /* at least one of the jobs needs to start at hmin or later */
11649 if( est1 < consdata->hmin && est2 < consdata->hmin )
11650 continue;
11651
11652 lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11653 lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11654
11655 /* at least one of the jobs needs to finish not later then hmin */
11656 if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11657 continue;
11658
11659 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11660 assert(idx2 >= 0);
11661 assert(idx1 != idx2);
11662
11663 if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11664 continue;
11665
11666 SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11667
11668 assert(tcliquegraph->durations[idx1] > 0);
11669 assert(tcliquegraph->durations[idx2] > 0);
11670
11671 tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11672 tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11673 }
11674 }
11675 }
11676 }
11677
11678 return SCIP_OKAY;
11679}
11680
11681/** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11682 * of jobs cannot run in parallel
11683 */
11684static
11686 SCIP* scip, /**< SCIP data structure */
11687 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11688 SCIP_CONS** conss, /**< array of cumulative constraints */
11689 int nconss /**< number of cumulative constraints */
11690 )
11691{
11692 assert(scip != NULL);
11693 assert(tcliquegraph != NULL);
11694
11695 /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11696 SCIP_CALL( projectVbd(scip, tcliquegraph) );
11697
11698 /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11699 transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11700
11701 /* constraints non-overlapping graph */
11702 SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11703
11704 return SCIP_OKAY;
11705}
11706
11707/** create cumulative constraint from conflict set */
11708static
11710 SCIP* scip, /**< SCIP data structure */
11711 const char* name, /**< constraint name */
11712 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11713 int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11714 int ncliquenodes /**< number of nodes in the clique */
11715 )
11716{
11717 SCIP_CONS* cons;
11718 SCIP_VAR** vars;
11719 int* durations;
11720 int* demands;
11721 int v;
11722
11726
11728
11729 /* collect variables, durations, and demands */
11730 for( v = 0; v < ncliquenodes; ++v )
11731 {
11732 durations[v] = tcliquegraph->durations[cliquenodes[v]];
11733 assert(durations[v] > 0);
11734 demands[v] = 1;
11735 vars[v] = tcliquegraph->vars[cliquenodes[v]];
11736 }
11737
11738 /* create (unary) cumulative constraint */
11739 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11741
11742 SCIP_CALL( SCIPaddCons(scip, cons) );
11743 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11744
11745 /* free buffers */
11746 SCIPfreeBufferArray(scip, &demands);
11747 SCIPfreeBufferArray(scip, &durations);
11749
11750 return SCIP_OKAY;
11751}
11752
11753/** search for cumulative constrainst */
11754static
11756 SCIP* scip, /**< SCIP data structure */
11757 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11758 int* naddconss /**< pointer to store the number of added constraints */
11759 )
11760{
11762 SCIP_Bool* precedencerow;
11763 SCIP_Bool* precedencecol;
11764 SCIP_Bool* demandrow;
11765 SCIP_Bool* demandcol;
11767 int* cliquenodes;
11768 int ncliquenodes;
11769 int cliqueweight;
11770 int ntreenodes;
11771 int nnodes;
11772 int nconss;
11773 int v;
11774
11775 nnodes = tcliquegraph->nnodes;
11776 nconss = 0;
11777
11778 /* initialize the weight of each job with its duration */
11779 for( v = 0; v < nnodes; ++v )
11780 {
11781 tcliquegraph->weights[v] = tcliquegraph->durations[v];
11782 }
11783
11789
11790 /* create a hash table to store all start time variables which are already covered by at least one clique */
11793
11794 /* for each variables/job we are ... */
11795 for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11796 {
11797 char name[SCIP_MAXSTRLEN];
11798 int c;
11799
11800 /* jobs with zero durations are skipped */
11801 if( tcliquegraph->durations[v] == 0 )
11802 continue;
11803
11804 /* check if the start time variable is already covered by at least one clique */
11805 if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11806 continue;
11807
11808 SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11809
11810 /* temporarily remove the connection via the precedence graph */
11811 for( c = 0; c < nnodes; ++c )
11812 {
11813 precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11814 precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11815
11816 demandrow[c] = tcliquegraph->demandmatrix[v][c];
11817 demandcol[c] = tcliquegraph->demandmatrix[c][v];
11818
11819#if 0
11820 if( precedencerow[c] || precedencecol[c] )
11821 {
11822 tcliquegraph->demandmatrix[v][c] = FALSE;
11823 tcliquegraph->demandmatrix[c][v] = FALSE;
11824 }
11825#endif
11826
11827 tcliquegraph->precedencematrix[c][v] = FALSE;
11828 tcliquegraph->precedencematrix[v][c] = FALSE;
11829 }
11830
11831 /* find (heuristically) maximum cliques which includes node v */
11833 tcliquegraph, tcliqueNewsolClique, NULL,
11835 10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11836
11837 SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11838
11839 if( ncliquenodes == 1 )
11840 continue;
11841
11842 /* construct constraint name */
11843 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11844
11846 nconss++;
11847
11848 /* all start time variable to covered hash table */
11849 for( c = 0; c < ncliquenodes; ++c )
11850 {
11851 SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11852 }
11853
11854 /* copy the precedence relations back */
11855 for( c = 0; c < nnodes; ++c )
11856 {
11857 tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11858 tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11859
11860 tcliquegraph->demandmatrix[v][c] = demandrow[c];
11861 tcliquegraph->demandmatrix[c][v] = demandcol[c];
11862 }
11863 }
11864
11866
11872
11873 (*naddconss) += nconss;
11874
11875 /* for the statistic we count the number added disjunctive constraints */
11877
11878 return SCIP_OKAY;
11879}
11880
11881/** create precedence constraint (as variable bound constraint */
11882static
11884 SCIP* scip, /**< SCIP data structure */
11885 const char* name, /**< constraint name */
11886 SCIP_VAR* var, /**< variable x that has variable bound */
11887 SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11888 int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11889 )
11890{
11891 SCIP_CONS* cons;
11892
11893 /* create variable bound constraint */
11894 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11896
11898
11899 /* add constraint to problem and release it */
11900 SCIP_CALL( SCIPaddCons(scip, cons) );
11901 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11902
11903 return SCIP_OKAY;
11904}
11905
11906/** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11907static
11909 SCIP* scip, /**< SCIP data structure */
11910 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11911 int source, /**< index of the source node */
11912 int sink, /**< index of the sink node */
11913 int* naddconss /**< pointer to store the number of added constraints */
11914 )
11915{
11918 SCIP_VAR** vars;
11919 int* cliquenodes;
11920 int nnodes;
11921 int lct;
11922 int est;
11923 int i;
11924
11925 int ntreenodes;
11926 int ncliquenodes;
11927
11928 /* check if source and sink are connencted */
11929 if( !tcliquegraph->precedencematrix[source][sink] )
11930 return SCIP_OKAY;
11931
11932 nnodes = tcliquegraph->nnodes;
11933 vars = tcliquegraph->vars;
11934
11935 /* reset the weights to zero */
11936 BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11937
11938 /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11939 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11941
11942 /* weight all jobs which run for sure between source and sink with their duration */
11943 for( i = 0; i < nnodes; ++i )
11944 {
11945 SCIP_VAR* var;
11946 int duration;
11947
11948 var = vars[i];
11949 assert(var != NULL);
11950
11951 duration = tcliquegraph->durations[i];
11952
11953 if( i == source || i == sink )
11954 {
11955 /* source and sink are not weighted */
11956 tcliquegraph->weights[i] = 0;
11957 }
11958 else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11959 {
11960 /* job i runs after source and before sink */
11961 tcliquegraph->weights[i] = duration;
11962 }
11964 && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11965 {
11966 /* job i run in between due the bounds of the start time variables */
11967 tcliquegraph->weights[i] = duration;
11968 }
11969 else
11970 tcliquegraph->weights[i] = 0;
11971 }
11972
11974
11975 /* find (heuristically) maximum cliques */
11977 tcliquegraph, tcliqueNewsolClique, NULL,
11979 10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11980
11981 if( ncliquenodes > 1 )
11982 {
11983 char name[SCIP_MAXSTRLEN];
11984 int distance;
11985
11986 /* construct constraint name */
11987 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11988
11989 /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11990 * duration of the source job
11991 */
11992 distance = cliqueweight + tcliquegraph->durations[source];
11993
11994 SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11995 (*naddconss)++;
11996 }
11997
11999
12000 return SCIP_OKAY;
12001}
12002
12003/** search for precedence constraints
12004 *
12005 * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
12006 * corresponding two jobs
12007 */
12008static
12010 SCIP* scip, /**< SCIP data structure */
12011 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
12012 int* naddconss /**< pointer to store the number of added constraints */
12013 )
12014{
12015 int* sources;
12016 int* sinks;
12017 int nconss;
12018 int nnodes;
12019 int nsources;
12020 int nsinks;
12021 int i;
12022
12023 nnodes = tcliquegraph->nnodes;
12024 nconss = 0;
12025
12026 nsources = 0;
12027 nsinks = 0;
12028
12031
12032 /* first collect all sources and sinks */
12033 for( i = 0; i < nnodes; ++i )
12034 {
12035 if( tcliquegraph->ninarcs[i] == 0 )
12036 {
12037 sources[nsources] = i;
12038 nsources++;
12039 }
12040
12041 if( tcliquegraph->ninarcs[i] == 0 )
12042 {
12043 sinks[nsinks] = i;
12044 nsinks++;
12045 }
12046 }
12047
12048 /* compute for each node a minimum distance to each sources and each sink */
12049 for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12050 {
12051 int j;
12052
12053 for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12054 {
12055 SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12056 }
12057
12058 for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12059 {
12060 SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12061 }
12062 }
12063
12064 (*naddconss) += nconss;
12065
12066 /* for the statistic we count the number added variable constraints */
12068
12071
12072 return SCIP_OKAY;
12073}
12074
12075/** initialize the assumed durations for each variable */
12076static
12078 SCIP* scip, /**< SCIP data structure */
12079 TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12080 SCIP_CONS** conss, /**< cumulative constraints */
12081 int nconss /**< number of cumulative constraints */
12082 )
12083{
12084 int c;
12085
12086 /* use the cumulative structure to define the duration we are using for each job */
12087 for( c = 0; c < nconss; ++c )
12088 {
12089 SCIP_CONSDATA* consdata;
12090 SCIP_VAR** vars;
12091 int nvars;
12092 int v;
12093
12094 consdata = SCIPconsGetData(conss[c]);
12095 assert(consdata != NULL);
12096
12097 vars = consdata->vars;
12098 nvars = consdata->nvars;
12099
12100 for( v = 0; v < nvars; ++v )
12101 {
12102 int idx;
12103
12104 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12105 assert(idx >= 0);
12106
12107 /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12108 * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12109 * general this is not the case. Therefore, the question would be which duration should be used?
12110 */
12111 tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12112 assert(tcliquegraph->durations[idx] > 0);
12113 }
12114 }
12115
12116 return SCIP_OKAY;
12117}
12118
12119/** create tclique graph */
12120static
12122 SCIP* scip, /**< SCIP data structure */
12123 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12124 )
12125{
12126 SCIP_VAR** vars;
12127 SCIP_HASHMAP* varmap;
12128 SCIP_Bool** precedencematrix;
12129 SCIP_Bool** demandmatrix;
12130 int* ninarcs;
12131 int* noutarcs;
12132 int* durations;
12133 int* weights;
12134 int nvars;
12135 int v;
12136
12139
12140 /* allocate memory for the tclique graph data structure */
12141 SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12142
12143 /* create the variable mapping hash map */
12145
12146 /* each active variables get a node in the graph */
12147 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12148
12149 /* allocate memory for the projected variables bound graph and the none overlapping graph */
12150 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12151 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12152
12153 /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12155 BMSclearMemoryArray(weights, nvars);
12156
12157 /* array to store the number of in arc of the precedence graph */
12159 BMSclearMemoryArray(ninarcs, nvars);
12160
12161 /* array to store the number of out arc of the precedence graph */
12162 SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12163 BMSclearMemoryArray(noutarcs, nvars);
12164
12165 /* array to store the used duration for each node */
12166 SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12167 BMSclearMemoryArray(durations, nvars);
12168
12169 for( v = 0; v < nvars; ++v )
12170 {
12171 SCIP_VAR* var;
12172
12173 var = vars[v];
12174 assert(var != NULL);
12175
12176 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12177 BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12178
12179 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12180 BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12181
12182 /* insert all active variables into the garph */
12184 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12185 }
12186
12187 (*tcliquegraph)->nnodes = nvars;
12188 (*tcliquegraph)->varmap = varmap;
12189 (*tcliquegraph)->precedencematrix = precedencematrix;
12190 (*tcliquegraph)->demandmatrix = demandmatrix;
12191 (*tcliquegraph)->weights = weights;
12192 (*tcliquegraph)->ninarcs = ninarcs;
12193 (*tcliquegraph)->noutarcs = noutarcs;
12194 (*tcliquegraph)->durations = durations;
12195 (*tcliquegraph)->size = nvars;
12196
12197 return SCIP_OKAY;
12198}
12199
12200/** frees the tclique graph */
12201static
12203 SCIP* scip, /**< SCIP data structure */
12204 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12205 )
12206{
12207 int v;
12208
12209 for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12210 {
12211 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12212 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12213 }
12214
12215 SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12216 SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12217 SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12218 SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12219 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12220 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12221 SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12222 SCIPhashmapFree(&(*tcliquegraph)->varmap);
12223
12224 SCIPfreeBuffer(scip, tcliquegraph);
12225}
12226
12227/** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12228 * constrains (disjunctive constraint)
12229 */
12230static
12232 SCIP* scip, /**< SCIP data structure */
12233 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12234 SCIP_CONS** conss, /**< array of cumulative constraints */
12235 int nconss, /**< number of cumulative constraints */
12236 int* naddconss /**< pointer to store the number of added constraints */
12237 )
12238{
12239 TCLIQUE_GRAPH* tcliquegraph;
12240
12241 /* create tclique graph */
12242 SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12243
12244 /* define for each job a duration */
12245 SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12246
12247 /* constuct incompatibility graph */
12248 SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12249
12250 /* search for new precedence constraints */
12251 if( conshdlrdata->detectvarbounds )
12252 {
12253 SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12254 }
12255
12256 /* search for new cumulative constraints */
12257 if( conshdlrdata->detectdisjunctive )
12258 {
12259 SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12260 }
12261
12262 /* free tclique graph data structure */
12263 freeTcliqueGraph(scip, &tcliquegraph);
12264
12265 return SCIP_OKAY;
12266}
12267
12268/** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12269static
12271 SCIP_CONSDATA* consdata /**< cumulative constraint data */
12272 )
12273{
12274 SCIP_VAR** vars;
12275 int nvars;
12276 int v;
12277
12278 if( consdata->validsignature )
12279 return;
12280
12281 vars = consdata->vars;
12282 nvars = consdata->nvars;
12283
12284 for( v = 0; v < nvars; ++v )
12285 {
12286 consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12287 }
12288
12289 consdata->validsignature = TRUE;
12290}
12291
12292/** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12293static
12295{ /*lint --e{715}*/
12296 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12297
12298 assert(consdata != NULL);
12301
12302 return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12303}
12304
12305/** run a pairwise comparison */
12306static
12308 SCIP* scip, /**< SCIP data structure */
12309 SCIP_CONS** conss, /**< array of cumulative constraints */
12310 int nconss, /**< number of cumulative constraints */
12311 int* ndelconss /**< pointer to store the number of deletedconstraints */
12312 )
12313{
12314 int i;
12315 int j;
12316
12317 for( i = 0; i < nconss; ++i )
12318 {
12321
12322 cons0 = conss[i];
12323 assert(cons0 != NULL);
12324
12326 assert(consdata0 != NULL);
12327
12329 assert(consdata0->validsignature);
12330
12331 for( j = i+1; j < nconss; ++j )
12332 {
12335
12336 cons1 = conss[j];
12337 assert(cons1 != NULL);
12338
12340 assert(consdata1 != NULL);
12341
12342 if( consdata0->capacity != consdata1->capacity )
12343 continue;
12344
12346 assert(consdata1->validsignature);
12347
12348 if( (consdata1->signature & (~consdata0->signature)) == 0 )
12349 {
12350 SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12351 SCIPswapPointers((void**)&cons0, (void**)&cons1);
12352 assert((consdata0->signature & (~consdata1->signature)) == 0);
12353 }
12354
12355 if( (consdata0->signature & (~consdata1->signature)) == 0 )
12356 {
12357 int* perm0;
12358 int* perm1;
12359 int v0;
12360 int v1;
12361
12362 if( consdata0->nvars > consdata1->nvars )
12363 continue;
12364
12365 if( consdata0->hmin < consdata1->hmin )
12366 continue;
12367
12368 if( consdata0->hmax > consdata1->hmax )
12369 continue;
12370
12373
12374 /* call sorting method */
12377
12378 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12379 {
12380 SCIP_VAR* var0;
12381 SCIP_VAR* var1;
12382 int idx0;
12383 int idx1;
12384 int comp;
12385
12386 idx0 = perm0[v0];
12387 idx1 = perm1[v1];
12388
12389 var0 = consdata0->vars[idx0];
12390
12391 var1 = consdata1->vars[idx1];
12392
12394
12395 if( comp == 0 )
12396 {
12397 int duration0;
12398 int duration1;
12399 int demand0;
12400 int demand1;
12401
12402 demand0 = consdata0->demands[idx0];
12403 duration0 = consdata0->durations[idx0];
12404
12405 demand1 = consdata1->demands[idx1];
12406 duration1 = consdata1->durations[idx1];
12407
12408 if( demand0 != demand1 )
12409 break;
12410
12411 if( duration0 != duration1 )
12412 break;
12413
12414 v0++;
12415 v1++;
12416 }
12417 else if( comp > 0 )
12418 v1++;
12419 else
12420 break;
12421 }
12422
12423 if( v0 == consdata0->nvars )
12424 {
12426 {
12428 }
12429
12430 /* coverity[swapped_arguments] */
12432
12434 (*ndelconss)++;
12435 }
12436
12439 }
12440 }
12441 }
12442
12443 return SCIP_OKAY;
12444}
12445
12446/** strengthen the variable bounds using the cumulative condition */
12447static
12449 SCIP* scip, /**< SCIP data structure */
12450 SCIP_CONS* cons, /**< constraint to propagate */
12451 int* nchgbds, /**< pointer to store the number of changed bounds */
12452 int* naddconss /**< pointer to store the number of added constraints */
12453 )
12454{
12455 SCIP_CONSDATA* consdata;
12456 SCIP_VAR** vars;
12457 int* durations;
12458 int* demands;
12459 int capacity;
12460 int nvars;
12461 int nconss;
12462 int i;
12463
12464 consdata = SCIPconsGetData(cons);
12465 assert(consdata != NULL);
12466
12467 /* check if the variable bounds got already strengthen by the cumulative constraint */
12468 if( consdata->varbounds )
12469 return SCIP_OKAY;
12470
12471 vars = consdata->vars;
12472 durations = consdata->durations;
12473 demands = consdata->demands;
12474 capacity = consdata->capacity;
12475 nvars = consdata->nvars;
12476
12477 nconss = 0;
12478
12479 for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12480 {
12481 SCIP_VAR** vbdvars;
12482 SCIP_VAR* var;
12483 SCIP_Real* vbdcoefs;
12484 SCIP_Real* vbdconsts;
12485 int nvbdvars;
12486 int b;
12487 int j;
12488
12489 var = consdata->vars[i];
12490 assert(var != NULL);
12491
12496
12497 for( b = 0; b < nvbdvars; ++b )
12498 {
12499 if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12500 {
12501 if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12502 {
12503 for( j = 0; j < nvars; ++j )
12504 {
12505 if( vars[j] == vbdvars[b] )
12506 break;
12507 }
12508 if( j == nvars )
12509 continue;
12510
12511 if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12512 {
12513 SCIP_Bool infeasible;
12514 char name[SCIP_MAXSTRLEN];
12515 int nlocalbdchgs;
12516
12517 SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12518
12519 /* construct constraint name */
12520 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12521
12522 SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12523 nconss++;
12524
12525 SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12526 assert(!infeasible);
12527
12528 (*nchgbds) += nlocalbdchgs;
12529 }
12530 }
12531 }
12532 }
12533 }
12534
12535 (*naddconss) += nconss;
12536
12537 consdata->varbounds = TRUE;
12538
12539 return SCIP_OKAY;
12540}
12541
12542/** helper function to enforce constraints */
12543static
12545 SCIP* scip, /**< SCIP data structure */
12546 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12547 SCIP_CONS** conss, /**< constraints to process */
12548 int nconss, /**< number of constraints */
12549 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12550 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12551 SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12552 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12553 )
12554{
12555 SCIP_CONSHDLRDATA* conshdlrdata;
12556
12557 assert(conshdlr != NULL);
12559 assert(nconss == 0 || conss != NULL);
12560 assert(result != NULL);
12561
12562 if( solinfeasible )
12563 {
12565 return SCIP_OKAY;
12566 }
12567
12568 SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12569 sol == NULL ? "LP" : "relaxation");
12570
12571 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12572 assert(conshdlrdata != NULL);
12573
12574 (*result) = SCIP_FEASIBLE;
12575
12576 if( conshdlrdata->usebinvars )
12577 {
12578 SCIP_Bool separated;
12579 SCIP_Bool cutoff;
12580 int c;
12581
12582 separated = FALSE;
12583
12584 /* first check if a constraints is violated */
12585 for( c = 0; c < nusefulconss; ++c )
12586 {
12587 SCIP_CONS* cons;
12588 SCIP_Bool violated;
12589
12590 cons = conss[c];
12591 assert(cons != NULL);
12592
12593 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12594
12595 if( !violated )
12596 continue;
12597
12599 if ( cutoff )
12600 {
12602 return SCIP_OKAY;
12603 }
12604 }
12605
12606 for( ; c < nconss && !separated; ++c )
12607 {
12608 SCIP_CONS* cons;
12609 SCIP_Bool violated;
12610
12611 cons = conss[c];
12612 assert(cons != NULL);
12613
12614 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12615
12616 if( !violated )
12617 continue;
12618
12620 if ( cutoff )
12621 {
12623 return SCIP_OKAY;
12624 }
12625 }
12626
12627 if( separated )
12628 (*result) = SCIP_SEPARATED;
12629 }
12630 else
12631 {
12632 SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12633 }
12634
12635 return SCIP_OKAY;
12636}
12637
12638/**@} */
12639
12640
12641/**@name Callback methods of constraint handler
12642 *
12643 * @{
12644 */
12645
12646/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12647static
12649{ /*lint --e{715}*/
12650 assert(scip != NULL);
12651 assert(conshdlr != NULL);
12653
12654 /* call inclusion method of constraint handler */
12656
12658
12659 *valid = TRUE;
12660
12661 return SCIP_OKAY;
12662}
12663
12664/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12665static
12667{ /*lint --e{715}*/
12668 SCIP_CONSHDLRDATA* conshdlrdata;
12669
12670 assert(conshdlr != NULL);
12672
12673 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12674 assert(conshdlrdata != NULL);
12675
12676#ifdef SCIP_STATISTIC
12677 if( !conshdlrdata->iscopy )
12678 {
12679 /* statisitc output if SCIP_STATISTIC is defined */
12680 SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12681 conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12682 SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12683 conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12684 SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12685 conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12686 }
12687#endif
12688
12689 conshdlrdataFree(scip, &conshdlrdata);
12690
12691 SCIPconshdlrSetData(conshdlr, NULL);
12692
12693 return SCIP_OKAY;
12694}
12695
12696
12697/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12698static
12700{ /*lint --e{715}*/
12701 SCIP_CONSHDLRDATA* conshdlrdata;
12702 int c;
12703
12704 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12705 assert(conshdlrdata != NULL);
12706
12707 conshdlrdata->detectedredundant = FALSE;
12708
12709 for( c = 0; c < nconss; ++c )
12710 {
12711 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12712 * hmax)
12713 */
12715 }
12716
12717 return SCIP_OKAY;
12718}
12719
12720
12721/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12722#ifdef SCIP_STATISTIC
12723static
12725{ /*lint --e{715}*/
12726 SCIP_CONSHDLRDATA* conshdlrdata;
12727 int c;
12728
12729 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12730 assert(conshdlrdata != NULL);
12731
12732 for( c = 0; c < nconss; ++c )
12733 {
12735
12736#if 0
12738#endif
12739 }
12740
12741 if( !conshdlrdata->iscopy )
12742 {
12743 SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12744 SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12745 SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12746 SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12747 SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12748 SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12749 SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12750 SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12751 SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12752 }
12753
12754 return SCIP_OKAY;
12755}
12756#endif
12757
12758
12759/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12760static
12762{ /*lint --e{715}*/
12763 SCIP_CONSDATA* consdata;
12764 int c;
12765
12766 assert(conshdlr != NULL);
12768
12769 /* release the rows of all constraints */
12770 for( c = 0; c < nconss; ++c )
12771 {
12772 consdata = SCIPconsGetData(conss[c]);
12773 assert(consdata != NULL);
12774
12775 /* free rows */
12776 SCIP_CALL( consdataFreeRows(scip, &consdata) );
12777 }
12778
12779 return SCIP_OKAY;
12780}
12781
12782/** frees specific constraint data */
12783static
12785{ /*lint --e{715}*/
12786 assert(conshdlr != NULL);
12788 assert(consdata != NULL );
12789 assert(*consdata != NULL );
12790
12791 /* if constraint belongs to transformed problem space, drop bound change events on variables */
12792 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12793 {
12794 SCIP_CONSHDLRDATA* conshdlrdata;
12795
12796 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12797 assert(conshdlrdata != NULL);
12798
12799 SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12800 }
12801
12802 /* free cumulative constraint data */
12803 SCIP_CALL( consdataFree(scip, consdata) );
12804
12805 return SCIP_OKAY;
12806}
12807
12808/** transforms constraint data into data belonging to the transformed problem */
12809static
12811{ /*lint --e{715}*/
12812 SCIP_CONSHDLRDATA* conshdlrdata;
12815
12816 assert(conshdlr != NULL);
12820
12823 assert(sourcedata->demandrows == NULL);
12824
12825 SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12826
12827 /* get event handler */
12828 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12829 assert(conshdlrdata != NULL);
12830 assert(conshdlrdata->eventhdlr != NULL);
12831
12832 /* create constraint data for target constraint */
12834 sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12836
12837 /* create target constraint */
12843
12844 /* catch bound change events of variables */
12845 SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12846
12847 return SCIP_OKAY;
12848}
12849
12850/** LP initialization method of constraint handler */
12851static
12853{
12854 SCIP_CONSHDLRDATA* conshdlrdata;
12855 int c;
12856
12858 assert(conshdlr != NULL);
12859 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12860 assert(conshdlrdata != NULL);
12861
12862 *infeasible = FALSE;
12863
12864 SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12865
12866 if( conshdlrdata->usebinvars )
12867 {
12868 /* add rows to LP */
12869 for( c = 0; c < nconss && !(*infeasible); ++c )
12870 {
12871 assert(SCIPconsIsInitial(conss[c]));
12872 SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12873
12874 if( conshdlrdata->cutsasconss )
12875 {
12877 }
12878 }
12879 }
12880
12881 /**@todo if we want to use only the integer variables; only these will be in cuts
12882 * create some initial cuts, currently these are only separated */
12883
12884 return SCIP_OKAY;
12885}
12886
12887/** separation method of constraint handler for LP solutions */
12888static
12890{
12891 SCIP_CONSHDLRDATA* conshdlrdata;
12892 SCIP_Bool cutoff;
12893 SCIP_Bool separated;
12894 int c;
12895
12896 SCIPdebugMsg(scip, "consSepalpCumulative\n");
12897
12898 assert(conshdlr != NULL);
12900 assert(nconss == 0 || conss != NULL);
12901 assert(result != NULL);
12902 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12903 assert(conshdlrdata != NULL);
12904
12905 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12906
12907 cutoff = FALSE;
12908 separated = FALSE;
12909 (*result) = SCIP_DIDNOTRUN;
12910
12911 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12912 return SCIP_OKAY;
12913
12914 (*result) = SCIP_DIDNOTFIND;
12915
12916 if( conshdlrdata->usebinvars )
12917 {
12918 /* check all useful cumulative constraints for feasibility */
12919 for( c = 0; c < nusefulconss && !cutoff; ++c )
12920 {
12922 }
12923
12924 if( !cutoff && conshdlrdata->usecovercuts )
12925 {
12926 for( c = 0; c < nusefulconss; ++c )
12927 {
12929 }
12930 }
12931 }
12932
12933 if( conshdlrdata->sepaold )
12934 {
12935 /* separate cuts containing only integer variables */
12936 for( c = 0; c < nusefulconss; ++c )
12937 {
12940 }
12941 }
12942
12943 if( cutoff )
12945 else if( separated )
12947
12948 return SCIP_OKAY;
12949}
12950
12951/** separation method of constraint handler for arbitrary primal solutions */
12952static
12954{ /*lint --e{715}*/
12955 SCIP_CONSHDLRDATA* conshdlrdata;
12956 SCIP_Bool cutoff;
12957 SCIP_Bool separated;
12958 int c;
12959
12960 assert(conshdlr != NULL);
12962 assert(nconss == 0 || conss != NULL);
12963 assert(result != NULL);
12964
12965 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12966 assert(conshdlrdata != NULL);
12967
12968 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12969 return SCIP_OKAY;
12970
12971 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12972
12973 cutoff = FALSE;
12974 separated = FALSE;
12975 (*result) = SCIP_DIDNOTFIND;
12976
12977 if( conshdlrdata->usebinvars )
12978 {
12979 /* check all useful cumulative constraints for feasibility */
12980 for( c = 0; c < nusefulconss && !cutoff; ++c )
12981 {
12983 }
12984
12985 if( !cutoff && conshdlrdata->usecovercuts )
12986 {
12987 for( c = 0; c < nusefulconss; ++c )
12988 {
12990 }
12991 }
12992 }
12993 if( conshdlrdata->sepaold )
12994 {
12995 /* separate cuts containing only integer variables */
12996 for( c = 0; c < nusefulconss; ++c )
12997 {
13000 }
13001 }
13002
13003 if( cutoff )
13005 else if( separated )
13007
13008 return SCIP_OKAY;
13009}
13010
13011/** constraint enforcing method of constraint handler for LP solutions */
13012static
13014{ /*lint --e{715}*/
13015 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
13016
13017 return SCIP_OKAY;
13018}
13019
13020/** constraint enforcing method of constraint handler for relaxation solutions */
13021static
13023{ /*lint --e{715}*/
13024 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
13025
13026 return SCIP_OKAY;
13027}
13028
13029/** constraint enforcing method of constraint handler for pseudo solutions */
13030static
13032{ /*lint --e{715}*/
13033 SCIP_CONSHDLRDATA* conshdlrdata;
13034
13035 SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
13036
13037 assert(conshdlr != NULL);
13039 assert(nconss == 0 || conss != NULL);
13040 assert(result != NULL);
13041
13042 if( objinfeasible )
13043 {
13045 return SCIP_OKAY;
13046 }
13047
13048 (*result) = SCIP_FEASIBLE;
13049
13050 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13051 assert(conshdlrdata != NULL);
13052
13053 SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13054
13055 return SCIP_OKAY;
13056}
13057
13058/** feasibility check method of constraint handler for integral solutions */
13059static
13061{ /*lint --e{715}*/
13062 int c;
13063
13064 assert(conshdlr != NULL);
13066 assert(nconss == 0 || conss != NULL);
13067 assert(result != NULL);
13068
13070
13071 SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13072
13073 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13074 {
13075 SCIP_Bool violated = FALSE;
13076
13077 SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13078
13079 if( violated )
13081 }
13082
13083 return SCIP_OKAY;
13084}
13085
13086/** domain propagation method of constraint handler */
13087static
13089{ /*lint --e{715}*/
13090 SCIP_CONSHDLRDATA* conshdlrdata;
13091 SCIP_Bool cutoff;
13092 int nchgbds;
13093 int ndelconss;
13094 int c;
13095#if 0
13096 int naggrvars = 0;
13097#endif
13098
13099 SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13100
13101 assert(conshdlr != NULL);
13103 assert(nconss == 0 || conss != NULL);
13104 assert(result != NULL);
13105
13106 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13107 assert(conshdlrdata != NULL);
13108
13109 nchgbds = 0;
13110 ndelconss = 0;
13111 cutoff = FALSE;
13112 (*result) = SCIP_DIDNOTRUN;
13113
13114 /* propgate all useful constraints */
13115 for( c = 0; c < nusefulconss && !cutoff; ++c )
13116 {
13117 SCIP_CONS* cons;
13118
13119 cons = conss[c];
13120 assert(cons != NULL);
13121
13122 if( SCIPgetDepth(scip) == 0 )
13123 {
13124#if 0
13126 &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13127#else
13129 &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13130#endif
13131 if( cutoff )
13132 break;
13133
13134 if( SCIPconsIsDeleted(cons) )
13135 continue;
13136 }
13137
13138 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13139 }
13140
13141 if( !cutoff && nchgbds == 0 )
13142 {
13143 /* propgate all other constraints */
13144 for( c = nusefulconss; c < nconss && !cutoff; ++c )
13145 {
13146 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13147 }
13148 }
13149
13150#if 0
13151 if( !cutoff && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 )
13152 {
13153 SCIP_CALL( propagateAllConss(scip, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13154 }
13155#endif
13156
13157 if( cutoff )
13158 {
13159 SCIPdebugMsg(scip, "detected infeasible\n");
13161 }
13162 else if( nchgbds > 0 )
13163 {
13164 SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13166 }
13167 else
13169
13170 return SCIP_OKAY;
13171}
13172
13173/** presolving method of constraint handler */
13174static
13176{ /*lint --e{715}*/
13177 SCIP_CONSHDLRDATA* conshdlrdata;
13178 SCIP_CONS* cons;
13179 SCIP_Bool cutoff;
13180 SCIP_Bool unbounded;
13181 int oldnfixedvars;
13182 int oldnchgbds;
13183 int oldndelconss;
13184 int oldnaddconss;
13185 int oldnupgdconss;
13186 int oldnchgsides;
13187 int oldnchgcoefs;
13188 int c;
13189
13190 assert(conshdlr != NULL);
13192 assert(scip != NULL);
13193 assert(result != NULL);
13194
13195 SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13196
13197 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13198 assert(conshdlrdata != NULL);
13199
13201
13202 oldnfixedvars = *nfixedvars;
13203 oldnchgbds = *nchgbds;
13204 oldnchgsides = *nchgsides;
13205 oldnchgcoefs = *nchgcoefs;
13206 oldnupgdconss = *nupgdconss;
13207 oldndelconss = *ndelconss;
13208 oldnaddconss = *naddconss;
13209 cutoff = FALSE;
13210 unbounded = FALSE;
13211
13212 /* process constraints */
13213 for( c = 0; c < nconss && !cutoff; ++c )
13214 {
13215 cons = conss[c];
13216
13217 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13218 * hmax)
13219 */
13221
13222 if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13223 {
13224#if 0
13225 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13226 nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13227#else
13228 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13229 nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13230#endif
13231
13232 if( cutoff || unbounded )
13233 break;
13234
13235 if( SCIPconsIsDeleted(cons) )
13236 continue;
13237 }
13238
13239 /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13240 if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13241 {
13242 SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13243 }
13244
13245 /* strengthen existing variable bounds using the cumulative condition */
13246 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13247 {
13248 SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13249 }
13250
13251 /* propagate cumulative constraint */
13252 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13253 assert(checkDemands(scip, cons) || cutoff);
13254 }
13255
13256 if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13257 {
13258 SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13259 }
13260
13261 /* only perform the detection of variable bounds and disjunctive constraint once */
13262 if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13263 && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13264 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13265 {
13266 /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13267 * propagation
13268 */
13269 SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13270 conshdlrdata->detectedredundant = TRUE;
13271 }
13272
13273 if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13274 {
13275 SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13276 }
13277
13278 SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13279 *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13280
13281 if( cutoff )
13283 else if( unbounded )
13285 else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13286 || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13288 else
13290
13291 return SCIP_OKAY;
13292}
13293
13294/** propagation conflict resolving method of constraint handler */
13295static
13297{ /*lint --e{715}*/
13298 SCIP_CONSHDLRDATA* conshdlrdata;
13299 SCIP_CONSDATA* consdata;
13300
13301 assert(conshdlr != NULL);
13303 assert(scip != NULL);
13304 assert(result != NULL);
13305 assert(infervar != NULL);
13306 assert(bdchgidx != NULL);
13307
13308 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13309 assert(conshdlrdata != NULL);
13310
13311 /* process constraint */
13312 assert(cons != NULL);
13313
13314 consdata = SCIPconsGetData(cons);
13315 assert(consdata != NULL);
13316
13317 SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13318 SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13320
13321 SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13322 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13323 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13324
13325 return SCIP_OKAY;
13326}
13327
13328/** variable rounding lock method of constraint handler */
13329static
13331{ /*lint --e{715}*/
13332 SCIP_CONSDATA* consdata;
13333 SCIP_VAR** vars;
13334 int v;
13335
13336 SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13337
13338 assert(scip != NULL);
13339 assert(cons != NULL);
13341
13342 consdata = SCIPconsGetData(cons);
13343 assert(consdata != NULL);
13344
13345 vars = consdata->vars;
13346 assert(vars != NULL);
13347
13348 for( v = 0; v < consdata->nvars; ++v )
13349 {
13350 if( consdata->downlocks[v] && consdata->uplocks[v] )
13351 {
13352 /* the integer start variable should not get rounded in both direction */
13353 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13354 }
13355 else if( consdata->downlocks[v] )
13356 {
13357 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13358 }
13359 else if( consdata->uplocks[v] )
13360 {
13361 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13362 }
13363 }
13364
13365 return SCIP_OKAY;
13366}
13367
13368
13369/** constraint display method of constraint handler */
13370static
13372{ /*lint --e{715}*/
13373 assert(scip != NULL);
13374 assert(conshdlr != NULL);
13375 assert(cons != NULL);
13376
13377 consdataPrint(scip, SCIPconsGetData(cons), file);
13378
13379 return SCIP_OKAY;
13380}
13381
13382/** constraint copying method of constraint handler */
13383static
13385{ /*lint --e{715}*/
13388 SCIP_VAR** vars;
13389 const char* consname;
13390
13391 int nvars;
13392 int v;
13393
13396
13397 /* get variables of the source constraint */
13398 nvars = sourceconsdata->nvars;
13399 sourcevars = sourceconsdata->vars;
13400
13401 (*valid) = TRUE;
13402
13403 if( nvars == 0 )
13404 return SCIP_OKAY;
13405
13406 /* allocate buffer array */
13408
13409 for( v = 0; v < nvars && *valid; ++v )
13410 {
13411 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13412 assert(!(*valid) || vars[v] != NULL);
13413 }
13414
13415 /* only create the target constraint, if all variables could be copied */
13416 if( *valid )
13417 {
13418 if( name != NULL )
13419 consname = name;
13420 else
13421 consname = SCIPconsGetName(sourcecons);
13422
13423 /* create a copy of the cumulative constraint */
13425 sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13426 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13427
13428 /* adjust left side if the time axis if needed */
13429 if( sourceconsdata->hmin > 0 )
13430 {
13432 }
13433
13434 /* adjust right side if the time axis if needed */
13435 if( sourceconsdata->hmax < INT_MAX )
13436 {
13438 }
13439 }
13440
13441 /* free buffer array */
13443
13444 return SCIP_OKAY;
13445}
13446
13447
13448/** constraint parsing method of constraint handler */
13449static
13451{ /*lint --e{715}*/
13452 SCIP_VAR** vars;
13453 SCIP_VAR* var;
13454 SCIP_Real value;
13456 char* endptr;
13457 int* demands;
13458 int* durations;
13459 int capacity;
13460 int duration;
13461 int demand;
13462 int hmin;
13463 int hmax;
13464 int varssize;
13465 int nvars;
13466
13467 SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13468
13469 *success = TRUE;
13470
13471 /* cutoff "cumulative" form the constraint string */
13473 str = endptr;
13474
13475 varssize = 100;
13476 nvars = 0;
13477
13478 /* allocate buffer array for variables */
13479 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13480 SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13481 SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13482
13483 do
13484 {
13486
13487 if( var == NULL )
13488 {
13489 endptr = strchr(endptr, ')');
13490
13491 if( endptr == NULL )
13492 *success = FALSE;
13493 else
13494 str = endptr;
13495
13496 break;
13497 }
13498
13499 str = endptr;
13501 duration = atoi(strvalue);
13502 str = endptr;
13503
13505 demand = atoi(strvalue);
13506 str = endptr;
13507
13508 SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13509
13510 vars[nvars] = var;
13511 demands[nvars] = demand;
13512 durations[nvars] = duration;
13513 nvars++;
13514 }
13515 while( *str != ')' );
13516
13517 if( *success )
13518 {
13519 /* parse effective time window */
13521 hmin = atoi(strvalue);
13522 str = endptr;
13523
13524 if( SCIPparseReal(scip, str, &value, &endptr) )
13525 {
13526 hmax = (int)(value);
13527 str = endptr;
13528
13529 /* parse capacity */
13531 str = endptr;
13532 if( SCIPparseReal(scip, str, &value, &endptr) )
13533 {
13534 capacity = (int)value;
13535
13536 /* create cumulative constraint */
13537 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13538 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13539
13540 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13541 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13542 }
13543 }
13544 }
13545
13546 /* free buffer arrays */
13547 SCIPfreeBufferArray(scip, &durations);
13548 SCIPfreeBufferArray(scip, &demands);
13550
13551 return SCIP_OKAY;
13552}
13553
13554
13555/** constraint method of constraint handler which returns the variables (if possible) */
13556static
13558{ /*lint --e{715}*/
13559 SCIP_CONSDATA* consdata;
13560
13561 consdata = SCIPconsGetData(cons);
13562 assert(consdata != NULL);
13563
13565 (*success) = FALSE;
13566 else
13567 {
13568 assert(vars != NULL);
13569
13570 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13571 (*success) = TRUE;
13572 }
13573
13574 return SCIP_OKAY;
13575}
13576
13577/** constraint method of constraint handler which returns the number of variables (if possible) */
13578static
13580{ /*lint --e{715}*/
13581 SCIP_CONSDATA* consdata;
13582
13583 consdata = SCIPconsGetData(cons);
13584 assert(consdata != NULL);
13585
13586 (*nvars) = consdata->nvars;
13587 (*success) = TRUE;
13588
13589 return SCIP_OKAY;
13590}
13591
13592/**@} */
13593
13594/**@name Callback methods of event handler
13595 *
13596 * @{
13597 */
13598
13599
13600/** execution method of event handler */
13601static
13603{ /*lint --e{715}*/
13604 SCIP_CONSDATA* consdata;
13605
13606 assert(scip != NULL);
13607 assert(eventhdlr != NULL);
13608 assert(eventdata != NULL);
13610 assert(event != NULL);
13611
13612 consdata = (SCIP_CONSDATA*)eventdata;
13613 assert(consdata != NULL);
13614
13615 /* mark the constraint to be not propagated */
13616 consdata->propagated = FALSE;
13617
13618 return SCIP_OKAY;
13619}
13620
13621/**@} */
13622
13623/*
13624 * constraint specific interface methods
13625 */
13626
13627/** creates the handler for cumulative constraints and includes it in SCIP */
13629 SCIP* scip /**< SCIP data structure */
13630 )
13631{
13632 SCIP_CONSHDLRDATA* conshdlrdata;
13633 SCIP_CONSHDLR* conshdlr;
13634 SCIP_EVENTHDLR* eventhdlr;
13635
13636 /* create event handler for bound change events */
13638
13639 /* create cumulative constraint handler data */
13640 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13641
13642 /* include constraint handler */
13646 conshdlrdata) );
13647
13648 assert(conshdlr != NULL);
13649
13650 /* set non-fundamental callbacks via specific setter functions */
13653#ifdef SCIP_STATISTIC
13655#endif
13673
13674 /* add cumulative constraint handler parameters */
13676 "constraints/" CONSHDLR_NAME "/ttinfer",
13677 "should time-table (core-times) propagator be used to infer bounds?",
13678 &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13680 "constraints/" CONSHDLR_NAME "/efcheck",
13681 "should edge-finding be used to detect an overload?",
13682 &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13684 "constraints/" CONSHDLR_NAME "/efinfer",
13685 "should edge-finding be used to infer bounds?",
13686 &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13688 "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13689 &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13691 "constraints/" CONSHDLR_NAME "/ttefcheck",
13692 "should time-table edge-finding be used to detect an overload?",
13693 &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13695 "constraints/" CONSHDLR_NAME "/ttefinfer",
13696 "should time-table edge-finding be used to infer bounds?",
13697 &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13698
13700 "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13701 &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13703 "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13704 &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13706 "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13707 &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13709 "constraints/" CONSHDLR_NAME "/cutsasconss",
13710 "should the cumulative constraint create cuts as knapsack constraints?",
13711 &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13713 "constraints/" CONSHDLR_NAME "/sepaold",
13714 "shall old sepa algo be applied?",
13715 &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13716
13718 "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13719 &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13720
13721 /* presolving parameters */
13723 "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13724 &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13726 "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13727 &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13729 "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13730 &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13732 "constraints/" CONSHDLR_NAME "/presolpairwise",
13733 "should pairwise constraint comparison be performed in presolving?",
13734 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13736 "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13737 &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13738
13740 "constraints/" CONSHDLR_NAME "/maxnodes",
13741 "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13742 &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13744 "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13745 &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13747 "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13748 &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13749
13750 /* conflict analysis parameters */
13752 "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13753 &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13754
13755 return SCIP_OKAY;
13756}
13757
13758/** creates and captures a cumulative constraint */
13760 SCIP* scip, /**< SCIP data structure */
13761 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13762 const char* name, /**< name of constraint */
13763 int nvars, /**< number of variables (jobs) */
13764 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13765 int* durations, /**< array containing corresponding durations */
13766 int* demands, /**< array containing corresponding demands */
13767 int capacity, /**< available cumulative capacity */
13768 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13769 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13770 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13771 * Usually set to TRUE. */
13772 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13773 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13774 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13775 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13776 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13777 * Usually set to TRUE. */
13778 SCIP_Bool local, /**< is constraint only valid locally?
13779 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13780 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13781 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13782 * adds coefficients to this constraint. */
13783 SCIP_Bool dynamic, /**< is constraint subject to aging?
13784 * Usually set to FALSE. Set to TRUE for own cuts which
13785 * are seperated as constraints. */
13786 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13787 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13788 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13789 * if it may be moved to a more global node?
13790 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13791 )
13792{
13793 SCIP_CONSHDLR* conshdlr;
13794 SCIP_CONSDATA* consdata;
13795
13796 assert(scip != NULL);
13797
13798 /* find the cumulative constraint handler */
13799 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13800 if( conshdlr == NULL )
13801 {
13802 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13803 return SCIP_PLUGINNOTFOUND;
13804 }
13805
13806 SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13807
13808 /* create constraint data */
13809 SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13810
13811 /* create constraint */
13812 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13813 initial, separate, enforce, check, propagate,
13814 local, modifiable, dynamic, removable, stickingatnode) );
13815
13817 {
13818 SCIP_CONSHDLRDATA* conshdlrdata;
13819
13820 /* get event handler */
13821 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13822 assert(conshdlrdata != NULL);
13823 assert(conshdlrdata->eventhdlr != NULL);
13824
13825 /* catch bound change events of variables */
13826 SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13827 }
13828
13829 return SCIP_OKAY;
13830}
13831
13832/** creates and captures a cumulative constraint
13833 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13834 * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13835 *
13836 * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13837 *
13838 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13839 */
13841 SCIP* scip, /**< SCIP data structure */
13842 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13843 const char* name, /**< name of constraint */
13844 int nvars, /**< number of variables (jobs) */
13845 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13846 int* durations, /**< array containing corresponding durations */
13847 int* demands, /**< array containing corresponding demands */
13848 int capacity /**< available cumulative capacity */
13849 )
13850{
13851 assert(scip != NULL);
13852
13853 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13855
13856 return SCIP_OKAY;
13857}
13858
13859/** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13861 SCIP* scip, /**< SCIP data structure */
13862 SCIP_CONS* cons, /**< constraint data */
13863 int hmin /**< left bound of time axis to be considered */
13864 )
13865{
13866 SCIP_CONSDATA* consdata;
13868 {
13869 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13870 return SCIP_INVALIDCALL;
13871 }
13872
13873 consdata = SCIPconsGetData(cons);
13874 assert(consdata != NULL);
13875 assert(hmin >= 0);
13877
13878 consdata->hmin = hmin;
13879
13880 return SCIP_OKAY;
13881}
13882
13883/** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13885 SCIP* scip, /**< SCIP data structure */
13886 SCIP_CONS* cons /**< constraint */
13887 )
13888{
13889 SCIP_CONSDATA* consdata;
13891 {
13892 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13893 SCIPABORT();
13894 return 0; /*lint !e527*/
13895 }
13896
13897 consdata = SCIPconsGetData(cons);
13898 assert(consdata != NULL);
13899
13900 return consdata->hmin;
13901}
13902
13903/** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13905 SCIP* scip, /**< SCIP data structure */
13906 SCIP_CONS* cons, /**< constraint data */
13907 int hmax /**< right bound of time axis to be considered */
13908 )
13909{
13910 SCIP_CONSDATA* consdata;
13912 {
13913 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13914 SCIPABORT();
13915 return SCIP_INVALIDCALL; /*lint !e527*/
13916 }
13917
13918 consdata = SCIPconsGetData(cons);
13919 assert(consdata != NULL);
13920 assert(hmax >= consdata->hmin);
13921
13922 consdata->hmax = hmax;
13923
13924 return SCIP_OKAY;
13925}
13926
13927/** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13929 SCIP* scip, /**< SCIP data structure */
13930 SCIP_CONS* cons /**< constraint */
13931 )
13932{
13933 SCIP_CONSDATA* consdata;
13935 {
13936 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13937 SCIPABORT();
13938 return 0; /*lint !e527*/
13939 }
13940
13941 consdata = SCIPconsGetData(cons);
13942 assert(consdata != NULL);
13943
13944 return consdata->hmax;
13945}
13946
13947/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13949 SCIP* scip, /**< SCIP data structure */
13950 SCIP_CONS* cons /**< constraint data */
13951 )
13952{
13953 SCIP_CONSDATA* consdata;
13954
13956 {
13957 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13958 SCIPABORT();
13959 return NULL; /*lint !e527*/
13960 }
13961
13962 consdata = SCIPconsGetData(cons);
13963 assert(consdata != NULL);
13964
13965 return consdata->vars;
13966}
13967
13968/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13970 SCIP* scip, /**< SCIP data structure */
13971 SCIP_CONS* cons /**< constraint data */
13972 )
13973{
13974 SCIP_CONSDATA* consdata;
13975
13977 {
13978 SCIPerrorMessage("constraint is not a cumulative constraint\n");
13979 SCIPABORT();
13980 return -1; /*lint !e527*/
13981 }
13982
13983 consdata = SCIPconsGetData(cons);
13984 assert(consdata != NULL);
13985
13986 return consdata->nvars;
13987}
13988
13989/** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13991 SCIP* scip, /**< SCIP data structure */
13992 SCIP_CONS* cons /**< constraint data */
13993 )
13994{
13995 SCIP_CONSDATA* consdata;
13996
13998 {
13999 SCIPerrorMessage("constraint is not a cumulative constraint\n");
14000 SCIPABORT();
14001 return -1; /*lint !e527*/
14002 }
14003
14004 consdata = SCIPconsGetData(cons);
14005 assert(consdata != NULL);
14006
14007 return consdata->capacity;
14008}
14009
14010/** returns the durations of the cumulative constraint */ /*lint -e{715}*/
14012 SCIP* scip, /**< SCIP data structure */
14013 SCIP_CONS* cons /**< constraint data */
14014 )
14015{
14016 SCIP_CONSDATA* consdata;
14017
14019 {
14020 SCIPerrorMessage("constraint is not a cumulative constraint\n");
14021 SCIPABORT();
14022 return NULL; /*lint !e527*/
14023 }
14024
14025 consdata = SCIPconsGetData(cons);
14026 assert(consdata != NULL);
14027
14028 return consdata->durations;
14029}
14030
14031/** returns the demands of the cumulative constraint */ /*lint -e{715}*/
14033 SCIP* scip, /**< SCIP data structure */
14034 SCIP_CONS* cons /**< constraint data */
14035 )
14036{
14037 SCIP_CONSDATA* consdata;
14038
14040 {
14041 SCIPerrorMessage("constraint is not a cumulative constraint\n");
14042 SCIPABORT();
14043 return NULL; /*lint !e527*/
14044 }
14045
14046 consdata = SCIPconsGetData(cons);
14047 assert(consdata != NULL);
14048
14049 return consdata->demands;
14050}
14051
14052/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14053 * given solution is satisfied
14054 */
14056 SCIP* scip, /**< SCIP data structure */
14057 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14058 int nvars, /**< number of variables (jobs) */
14059 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14060 int* durations, /**< array containing corresponding durations */
14061 int* demands, /**< array containing corresponding demands */
14062 int capacity, /**< available cumulative capacity */
14063 int hmin, /**< left bound of time axis to be considered (including hmin) */
14064 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14065 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14066 SCIP_CONS* cons, /**< constraint which is checked */
14067 SCIP_Bool printreason /**< should the reason for the violation be printed? */
14068 )
14069{
14070 assert(scip != NULL);
14071 assert(violated != NULL);
14072
14073 SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14074 violated, cons, printreason) );
14075
14076 return SCIP_OKAY;
14077}
14078
14079/** normalize cumulative condition */ /*lint -e{715}*/
14081 SCIP* scip, /**< SCIP data structure */
14082 int nvars, /**< number of start time variables (activities) */
14083 SCIP_VAR** vars, /**< array of start time variables */
14084 int* durations, /**< array of durations */
14085 int* demands, /**< array of demands */
14086 int* capacity, /**< pointer to store the changed cumulative capacity */
14087 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14088 int* nchgsides /**< pointer to count number of side changes */
14089 )
14090{ /*lint --e{715}*/
14091 normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
14092
14093 return SCIP_OKAY;
14094}
14095
14096/** searches for a time point within the cumulative condition were the cumulative condition can be split */
14098 SCIP* scip, /**< SCIP data structure */
14099 int nvars, /**< number of variables (jobs) */
14100 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14101 int* durations, /**< array containing corresponding durations */
14102 int* demands, /**< array containing corresponding demands */
14103 int capacity, /**< available cumulative capacity */
14104 int* hmin, /**< pointer to store the left bound of the effective horizon */
14105 int* hmax, /**< pointer to store the right bound of the effective horizon */
14106 int* split /**< point were the cumulative condition can be split */
14107 )
14108{
14109 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14110 hmin, hmax, split) );
14111
14112 return SCIP_OKAY;
14113}
14114
14115/** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14117 SCIP* scip, /**< SCIP data structure */
14118 int nvars, /**< number of start time variables (activities) */
14119 SCIP_VAR** vars, /**< array of start time variables */
14120 int* durations, /**< array of durations */
14121 int hmin, /**< left bound of time axis to be considered */
14122 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14123 SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14124 SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14125 SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14126 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14127 int* nfixedvars, /**< pointer to store the number of fixed variables */
14128 int* nchgsides, /**< pointer to store the number of changed sides */
14129 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14130 )
14131{
14132 if( nvars <= 1 )
14133 return SCIP_OKAY;
14134
14135 /* presolve constraint form the earlier start time point of view */
14136 SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14137 irrelevants, nfixedvars, nchgsides, cutoff) );
14138
14139 /* presolve constraint form the latest completion time point of view */
14140 SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14141 irrelevants, nfixedvars, nchgsides, cutoff) );
14142
14143 return SCIP_OKAY;
14144}
14145
14146/** propagate the given cumulative condition */
14148 SCIP* scip, /**< SCIP data structure */
14149 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14150 int nvars, /**< number of variables (jobs) */
14151 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14152 int* durations, /**< array containing corresponding durations */
14153 int* demands, /**< array containing corresponding demands */
14154 int capacity, /**< available cumulative capacity */
14155 int hmin, /**< left bound of time axis to be considered (including hmin) */
14156 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14157 SCIP_CONS* cons, /**< constraint which gets propagated */
14158 int* nchgbds, /**< pointer to store the number of variable bound changes */
14159 SCIP_Bool* initialized, /**< was conflict analysis initialized */
14160 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14161 SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14162 )
14163{
14164 SCIP_CONSHDLR* conshdlr;
14165 SCIP_CONSHDLRDATA* conshdlrdata;
14166 SCIP_Bool redundant;
14167
14168 assert(scip != NULL);
14169 assert(cons != NULL);
14170 assert(initialized != NULL);
14171 assert(*initialized == FALSE);
14172 assert(cutoff != NULL);
14173 assert(*cutoff == FALSE);
14174
14175 /* find the cumulative constraint handler */
14176 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14177 if( conshdlr == NULL )
14178 {
14179 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14180 return SCIP_PLUGINNOTFOUND;
14181 }
14182
14183 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14184 assert(conshdlrdata != NULL);
14185
14186 redundant = FALSE;
14187
14188 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14189 nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14190 nchgbds, &redundant, initialized, explanation, cutoff) );
14191
14192 return SCIP_OKAY;
14193}
14194
14195/** resolve propagation w.r.t. the cumulative condition */
14197 SCIP* scip, /**< SCIP data structure */
14198 int nvars, /**< number of start time variables (activities) */
14199 SCIP_VAR** vars, /**< array of start time variables */
14200 int* durations, /**< array of durations */
14201 int* demands, /**< array of demands */
14202 int capacity, /**< cumulative capacity */
14203 int hmin, /**< left bound of time axis to be considered (including hmin) */
14204 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14205 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14206 int inferinfo, /**< the user information */
14207 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14208 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14209 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14210 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14211 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14212 )
14213{
14214 SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14215 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14216
14217 return SCIP_OKAY;
14218}
14219
14220/** this method visualizes the cumulative structure in GML format */
14222 SCIP* scip, /**< SCIP data structure */
14223 SCIP_CONS* cons /**< cumulative constraint */
14224 )
14225{
14226 SCIP_CONSDATA* consdata;
14228 FILE* file;
14229 SCIP_VAR* var;
14230 char filename[SCIP_MAXSTRLEN];
14231 int nvars;
14232 int v;
14233
14234 SCIP_RETCODE retcode = SCIP_OKAY;
14235
14236 /* open file */
14237 (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14238 file = fopen(filename, "w");
14239
14240 /* check if the file was open */
14241 if( file == NULL )
14242 {
14243 SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14244 SCIPprintSysError(filename);
14245 return SCIP_FILECREATEERROR;
14246 }
14247
14248 consdata = SCIPconsGetData(cons);
14249 assert(consdata != NULL);
14250
14251 nvars = consdata->nvars;
14252
14255
14256 /* create opening of the GML format */
14258
14259 for( v = 0; v < nvars; ++v )
14260 {
14261 char color[SCIP_MAXSTRLEN];
14262
14263 var = consdata->vars[v];
14264 assert(var != NULL);
14265
14267
14269 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14270 else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14271 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14272 else
14273 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14274
14275 SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14276 }
14277
14278 for( v = 0; v < nvars; ++v )
14279 {
14280 SCIP_VAR** vbdvars;
14281 int nvbdvars;
14282 int b;
14283
14284 var = consdata->vars[v];
14285 assert(var != NULL);
14286
14289
14290 for( b = 0; b < nvbdvars; ++b )
14291 {
14292 if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14293 {
14294 SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14295 }
14296 }
14297
14298#if 0
14301
14302 for( b = 0; b < nvbdvars; ++b )
14303 {
14305 {
14306 SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14307 }
14308 }
14309#endif
14310 }
14311
14312 /* create closing of the GML format */
14313 SCIPgmlWriteClosing(file);
14314TERMINATE:
14315 /* close file */
14316 fclose(file);
14317
14319
14320 return retcode;
14321}
14322
14323/** sets method to solve an individual cumulative condition */
14325 SCIP* scip, /**< SCIP data structure */
14326 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14327 )
14328{
14329 SCIP_CONSHDLR* conshdlr;
14330 SCIP_CONSHDLRDATA* conshdlrdata;
14331
14332 /* find the cumulative constraint handler */
14333 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14334 if( conshdlr == NULL )
14335 {
14336 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14337 return SCIP_PLUGINNOTFOUND;
14338 }
14339
14340 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14341 assert(conshdlrdata != NULL);
14342
14343 conshdlrdata->solveCumulative = solveCumulative;
14344
14345 return SCIP_OKAY;
14346}
14347
14348/** solves given cumulative condition as independent sub problem
14349 *
14350 * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14351 * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14352 * solver was interrupted.
14353 */
14355 SCIP* scip, /**< SCIP data structure */
14356 int njobs, /**< number of jobs (activities) */
14357 SCIP_Real* ests, /**< array with the earlier start time for each job */
14358 SCIP_Real* lsts, /**< array with the latest start time for each job */
14359 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14360 int* durations, /**< array of durations */
14361 int* demands, /**< array of demands */
14362 int capacity, /**< cumulative capacity */
14363 int hmin, /**< left bound of time axis to be considered (including hmin) */
14364 int hmax, /**< right bound of time axis to be considered (not including hmax) */
14365 SCIP_Real timelimit, /**< time limit for solving in seconds */
14366 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14367 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14368 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14369 SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14370 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14371 SCIP_Bool* error /**< pointer to store if an error occurred */
14372 )
14373{
14374 SCIP_CONSHDLR* conshdlr;
14375 SCIP_CONSHDLRDATA* conshdlrdata;
14376
14377 (*solved) = TRUE;
14378 (*infeasible) = FALSE;
14379 (*unbounded) = FALSE;
14380 (*error) = FALSE;
14381
14382 if( njobs == 0 )
14383 return SCIP_OKAY;
14384
14385 /* find the cumulative constraint handler */
14386 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14387 if( conshdlr == NULL )
14388 {
14389 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14390 (*error) = TRUE;
14391 return SCIP_PLUGINNOTFOUND;
14392 }
14393
14394 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14395 assert(conshdlrdata != NULL);
14396
14397 /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14398 if( timelimit > 0.0 && memorylimit > 10 )
14399 {
14400 SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14401 hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14402 }
14403
14404 return SCIP_OKAY;
14405}
14406
14407/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14408 * completion time
14409 */
14411 SCIP* scip, /**< SCIP data structure */
14412 SCIP_PROFILE* profile, /**< resource profile */
14413 int nvars, /**< number of variables (jobs) */
14414 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14415 int* durations, /**< array containing corresponding durations */
14416 int* demands /**< array containing corresponding demands */
14417 )
14418{
14419 SCIP_VAR* var;
14420 SCIP_HASHMAP* addedvars;
14421 int* copydemands;
14422 int* perm;
14423 int duration;
14424 int impliedest;
14425 int est;
14426 int impliedlct;
14427 int lct;
14428 int v;
14429
14430 /* create hash map for variables which are added, mapping to their duration */
14432
14435
14436 /* sort variables w.r.t. job demands */
14437 for( v = 0; v < nvars; ++v )
14438 {
14439 copydemands[v] = demands[v];
14440 perm[v] = v;
14441 }
14443
14444 /* add each job with its earliest start and latest completion time into the resource profile */
14445 for( v = 0; v < nvars; ++v )
14446 {
14447 int idx;
14448
14449 idx = perm[v];
14450 assert(idx >= 0 && idx < nvars);
14451
14452 var = vars[idx];
14453 assert(var != NULL);
14454
14455 duration = durations[idx];
14456 assert(duration > 0);
14457
14459 SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14460
14461 lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14462 SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14463
14464 if( impliedest < impliedlct )
14465 {
14466 SCIP_Bool infeasible;
14467 int pos;
14468
14469 SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14470 assert(!infeasible);
14471 assert(pos == -1);
14472 }
14473
14474 if( est == impliedest && lct == impliedlct )
14475 {
14476 SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14477 }
14478 }
14479
14481 SCIPfreeBufferArray(scip, &perm);
14482
14483 SCIPhashmapFree(&addedvars);
14484
14485 return SCIP_OKAY;
14486}
14487
14488/** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14490 SCIP* scip, /**< SCIP data structure */
14491 SCIP_PROFILE* profile, /**< worst case resource profile */
14492 int capacity /**< capacity to check */
14493 )
14494{
14495 int* timepoints;
14496 int* loads;
14497 int ntimepoints;
14498 int t;
14499
14500 ntimepoints = SCIPprofileGetNTimepoints(profile);
14501 timepoints = SCIPprofileGetTimepoints(profile);
14502 loads = SCIPprofileGetLoads(profile);
14503
14504 /* find first time point which potentially violates the capacity restriction */
14505 for( t = 0; t < ntimepoints - 1; ++t )
14506 {
14507 /* check if the time point exceed w.r.t. worst case profile the capacity */
14508 if( loads[t] > capacity )
14509 {
14510 assert(t == 0 || loads[t-1] <= capacity);
14511 return timepoints[t];
14512 }
14513 }
14514
14515 return INT_MAX;
14516}
14517
14518/** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */ /*lint -e{715}*/
14520 SCIP* scip, /**< SCIP data structure */
14521 SCIP_PROFILE* profile, /**< worst case profile */
14522 int capacity /**< capacity to check */
14523 )
14524{
14525 int* timepoints;
14526 int* loads;
14527 int ntimepoints;
14528 int t;
14529
14530 ntimepoints = SCIPprofileGetNTimepoints(profile);
14531 timepoints = SCIPprofileGetTimepoints(profile);
14532 loads = SCIPprofileGetLoads(profile);
14533
14534 /* find last time point which potentially violates the capacity restriction */
14535 for( t = ntimepoints - 1; t >= 0; --t )
14536 {
14537 /* check if at time point t the worst case resource profile exceeds the capacity */
14538 if( loads[t] > capacity )
14539 {
14540 assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14541 return timepoints[t+1];
14542 }
14543 }
14544
14545 return INT_MIN;
14546}
static long bound
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
SCIP_VAR ** b
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 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)
#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_Longint computeCoreWithInterval(int begin, int end, int ect, int lst)
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
#define DEFAULT_LOCALCUTS
static SCIP_RETCODE checkOverloadViaThetaTree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool propest, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
#define DEFAULT_COEFTIGHTENING
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
static SCIP_RETCODE createPrecedenceCons(SCIP *scip, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, int distance)
#define DEFAULT_MAXNODES
static SCIP_Bool isConsIndependently(SCIP_CONS *cons)
#define CONSHDLR_PROP_TIMING
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_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_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_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
#define DEFAULT_EFCHECK
static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
#define DEFAULT_DETECTDISJUNCTIVE
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
static INFERINFO getInferInfo(PROPRULE proprule, int data1, int data2)
static SCIP_RETCODE setupAndSolveCumulativeSubscip(SCIP *subscip, SCIP_Real *objvals, int *durations, int *demands, int njobs, int capacity, int hmin, int hmax, SCIP_Longint maxnodes, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *solved, SCIP_Bool *error)
static int computeOverlap(int begin, int end, int est, int lst, int duration)
static SCIP_Longint computeTotalEnergy(int *durations, int *demands, int njobs)
static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
static SCIP_RETCODE respropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, INFERINFO inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_RETCODE removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
static INFERINFO intToInferInfo(int i)
static void createSelectedSortedEventpointsSol(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *starttimes, int *endtimes, int *startindices, int *endindices, int *nvars, SCIP_Bool lower)
static void updateEnvelope(SCIP *scip, SCIP_BTNODE *node)
static SCIP_RETCODE propagateEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
struct SCIP_NodeData SCIP_NODEDATA
#define DEFAULT_CUTSASCONSS
#define DEFAULT_DUALPRESOLVE
static SCIP_RETCODE analyzeEnergyRequirement(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int begin, int end, SCIP_VAR *infervar, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation)
static SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
static SCIP_RETCODE applyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_Real leftub, SCIP_Real rightlb, SCIP_Real *leftimpllbs, SCIP_Real *leftimplubs, SCIP_Real *leftproplbs, SCIP_Real *leftpropubs, SCIP_Real *rightimpllbs, SCIP_Real *rightimplubs, SCIP_Real *rightproplbs, SCIP_Real *rightpropubs, int *nfixedvars, SCIP_Bool *success, SCIP_Bool *cutoff)
#define DEFAULT_TTEFCHECK
@ PROPRULE_3_TTEF
@ PROPRULE_0_INVALID
@ PROPRULE_1_CORETIMES
@ PROPRULE_2_EDGEFINDING
static void normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_Bool inferInfoIsValid(INFERINFO inferinfo)
static void computeCoreEnergyAfter(SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
static SCIP_RETCODE createCumulativeCons(SCIP *scip, const char *name, TCLIQUE_GRAPH *tcliquegraph, int *cliquenodes, int ncliquenodes)
static void collectDataTTEF(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int hmin, int hmax, int *permests, int *ests, int *permlcts, int *lcts, int *ects, int *lsts, int *flexenergies)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR **vars, SCIP_CONS **linkingconss, int *durations, int *demands, int nvars, int capacity, int hmin, int hmax, SCIP_Bool check)
static SCIP_RETCODE createCoverCutsTimepoint(SCIP *scip, SCIP_CONS *cons, int *startvalues, int time)
static SCIP_RETCODE tightenLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int ect, int lct, int begin, int end, SCIP_Longint energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
static SCIP_RETCODE presolveConsLct(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
static int inferInfoGetData2(INFERINFO inferinfo)
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_RETCODE propagateCumulativeCondition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *redundant, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_RETCODE resolvePropagationCoretimes(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferdemand, int inferpeak, int relaxedpeak, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool usebdwidening, int *provedpeak, SCIP_Bool *explanation)
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE collectBinaryVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***vars, int **coefs, int *nvars, int *startindices, int curtime, int nstarted, int nfinished)
#define DEFAULT_USEADJUSTEDJOBS
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
static void collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
#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 SCIP_RETCODE coretimesUpdateLb(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *infeasible)
static SCIP_RETCODE solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
#define 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 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 SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
#define DEFAULT_TTINFER
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE removeOversizedJobs(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *nchgcoefs, int *naddconss, SCIP_Bool *cutoff)
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
#define CONSHDLR_NAME
static int inferInfoToInt(INFERINFO inferinfo)
#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_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 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 SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
#define SCIP_DECL_SOLVECUMULATIVE(x)
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE 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_RETCODE SCIPsetSolveCumulative(SCIP *scip,)
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsolveCumulative(SCIP *scip, int njobs, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Real *objvals, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *linkvar, SCIP_VAR **binvars, SCIP_Real *vals, int nbinvars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPrespropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool *explanation, SCIP_RESULT *result)
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
SCIP_RETCODE 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)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_RETCODE SCIPfree(SCIP **scip)
SCIP_RETCODE SCIPcreate(SCIP **scip)
SCIP_STATUS SCIPgetStatus(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c: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,...)
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
#define SCIPdebugMsg
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)
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4227
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:492
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition scip_cons.c:281
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:323
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:808
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:785
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4197
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:941
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4217
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:854
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c: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)
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)
SCIP_RETCODE SCIPsolve(SCIP *scip)
int SCIPgetNRuns(SCIP *scip)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c: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:5205
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:4353
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:1482
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:8403
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:5617
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:5322
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:1796
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:4261
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition scip_var.c:6663
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:4439
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2130
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:1250
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:8717
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:8278
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:5503
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:1994
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:8631
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
return SCIP_OKAY
int c
SCIP_Bool cutoff
SCIP_Real objval
static SCIP_SOL * sol
int r
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
int nbinvars
#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)
#define SCIPstatisticPrintf
#define SCIPdebugMessage
Definition pub_message.h:96
#define SCIPstatistic(x)
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
default SCIP plugins
tclique user interface
#define TCLIQUE_GETWEIGHTS(x)
Definition tclique.h:105
#define TCLIQUE_GETNNODES(x)
Definition tclique.h:97
#define TCLIQUE_ISEDGE(x)
Definition tclique.h:115
#define TCLIQUE_SELECTADJNODES(x)
Definition tclique.h:130
enum TCLIQUE_Status TCLIQUE_STATUS
Definition tclique.h:68
int TCLIQUE_WEIGHT
Definition tclique.h:48
void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition tclique.h:49
#define TCLIQUE_NEWSOL(x)
Definition tclique.h:88
@ SCIP_CONFTYPE_PROPAGATION
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:866
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:768
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:505
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:884
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:611
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:844
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:560
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:675
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:809
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:173
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:253
#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
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:188
#define SCIP_DECL_SORTINDCOMP(x)
Definition type_misc.h:180
@ SCIP_PARAMEMPHASIS_CPSOLVER
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_UNBOUNDED
Definition type_result.h:47
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_FILECREATEERROR
@ SCIP_INVALIDDATA
@ SCIP_PLUGINNOTFOUND
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
@ 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:54
@ SCIP_STATUS_UNBOUNDED
Definition type_stat.h:63
@ SCIP_STATUS_UNKNOWN
Definition type_stat.h:42
@ 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_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