Scippy

    SCIP

    Solving Constraint Integer Programs

    cons_cumulative.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file cons_cumulative.c
    26 * @ingroup DEFPLUGINS_CONS
    27 * @brief constraint handler for cumulative constraints
    28 * @author Timo Berthold
    29 * @author Stefan Heinz
    30 * @author Jens Schulz
    31 *
    32 * Given:
    33 * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
    34 * their demands \f$d_j\f$.
    35 * - an integer resource capacity \f$C\f$
    36 *
    37 * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
    38 *
    39 * Separation:
    40 * - can be done using binary start time model, see Pritskers, Watters and Wolfe
    41 * - or by just separating relatively weak cuts on the integer start time variables
    42 *
    43 * Propagation:
    44 * - time tabling, Klein & Scholl (1999)
    45 * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
    46 * (2009)
    47 * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
    48 *
    49 */
    50
    51/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    52
    53#include <assert.h>
    54#include <string.h>
    55
    56#include "tclique/tclique.h"
    58#include "scip/cons_linking.h"
    59#include "scip/cons_knapsack.h"
    60#include "scip/scipdefplugins.h"
    61
    62/**@name Constraint handler properties
    63 *
    64 * @{
    65 */
    66
    67/* constraint handler properties */
    68#define CONSHDLR_NAME "cumulative"
    69#define CONSHDLR_DESC "cumulative constraint handler"
    70#define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
    71#define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
    72#define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
    73#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
    74#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
    75#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
    76 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
    77#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
    78#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
    79#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
    80#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
    81
    82#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
    83#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
    84
    85/**@} */
    86
    87/**@name Default parameter values
    88 *
    89 * @{
    90 */
    91
    92/* default parameter values */
    93#define DEFAULT_MAXTIME 2000000000 /** < maximum range for time horizon (to avoid integer overflow) */
    94
    95/* separation */
    96#define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
    97#define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
    98#define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
    99#define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
    100#define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
    101
    102/* propagation */
    103#define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
    104#define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
    105#define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
    106#define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
    107#define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
    108#define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
    109
    110/* presolving */
    111#define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
    112#define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
    113#define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
    114#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
    115#define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
    116#define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
    117#define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
    118#define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
    119
    120/* enforcement */
    121#define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
    122
    123/* conflict analysis */
    124#define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
    125
    126/**@} */
    127
    128/**@name Event handler properties
    129 *
    130 * @{
    131 */
    132
    133#define EVENTHDLR_NAME "cumulative"
    134#define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
    135
    136/**@} */
    137
    138/*
    139 * Data structures
    140 */
    141
    142/** constraint data for cumulative constraints */
    143struct SCIP_ConsData
    144{
    145 SCIP_VAR** vars; /**< array of variable representing the start time of each job */
    146 SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
    147 SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
    148 SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
    149 SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
    150 SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
    151 SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
    152 int* demands; /**< array containing corresponding demands */
    153 int* durations; /**< array containing corresponding durations */
    154 SCIP_Real resstrength1; /**< stores the resource strength 1*/
    155 SCIP_Real resstrength2; /**< stores the resource strength 2 */
    156 SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
    157 SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
    158 SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
    159 SCIP_Real estimatedstrength;
    160 int nvars; /**< number of variables */
    161 int varssize; /**< size of the arrays */
    162 int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
    163 int demandrowssize; /**< size of array rows of demand rows */
    164 int nscoverrows; /**< number of rows of small cover cuts */
    165 int scoverrowssize; /**< size of array of small cover cuts */
    166 int nbcoverrows; /**< number of rows of big cover cuts */
    167 int bcoverrowssize; /**< size of array of big cover cuts */
    168 int capacity; /**< available cumulative capacity */
    169
    170 int hmin; /**< left bound of time axis to be considered (including hmin) */
    171 int hmax; /**< right bound of time axis to be considered (not including hmax) */
    172
    173 unsigned int signature; /**< constraint signature which is need for pairwise comparison */
    174
    175 unsigned int validsignature:1; /**< is the signature valid */
    176 unsigned int normalized:1; /**< is the constraint normalized */
    177 unsigned int covercuts:1; /**< cover cuts are created? */
    178 unsigned int propagated:1; /**< is constraint propagted */
    179 unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
    180 unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
    181
    182#ifdef SCIP_STATISTIC
    183 int maxpeak;
    184#endif
    185};
    186
    187/** constraint handler data */
    188struct SCIP_ConshdlrData
    189{
    190 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
    191
    192 SCIP_Bool usebinvars; /**< should the binary variables be used? */
    193 SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
    194 SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
    195 SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
    196 SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
    197 SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
    198 SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
    199 SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
    200 SCIP_Bool localcuts; /**< should cuts be added only locally? */
    201 SCIP_Bool usecovercuts; /**< should covering cuts be added? */
    202 SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
    203
    204 SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
    205
    206 SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
    207 SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
    208 SCIP_Bool normalize; /**< should demands and capacity be normalized? */
    209 SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
    210 SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
    211 SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
    212 SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
    213 SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
    214 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
    215
    216 int maxtime; /**< maximum range for time horizon (to avoid integer overflow) */
    217 SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
    218
    219 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
    220
    221 /* statistic values which are collected if SCIP_STATISTIC is defined */
    222#ifdef SCIP_STATISTIC
    223 SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
    224 SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
    225 SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
    226 SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
    227 SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
    228 SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
    229 SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
    230 SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
    231 SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
    232 SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
    233
    234 int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
    235 int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
    236 int nremovedlocks; /**< number of times a up or down lock was removed */
    237 int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
    238 int ndecomps; /**< number of times a constraint was decomposed */
    239 int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
    240 int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
    241 int naddedvarbounds; /**< number of added variable bounds constraints */
    242 int naddeddisjunctives; /**< number of added disjunctive constraints */
    243
    244 SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
    245#endif
    246};
    247
    248/**@name Inference Information Methods
    249 *
    250 * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
    251 * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
    252 * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
    253 *
    254 * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
    255 * change and the earliest start and latest completion time of all jobs in the conflict set.
    256 *
    257 * @{
    258 */
    259
    260/** Propagation rules */
    262{
    263 PROPRULE_0_INVALID = 0, /**< invalid inference information */
    264 PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
    265 PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
    266 PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
    268typedef enum Proprule PROPRULE;
    269
    270/** inference information */
    271struct InferInfo
    272{
    273 union
    274 {
    275 /** struct to use the inference information */
    276 struct
    277 {
    278 unsigned int proprule:2; /**< propagation rule that was applied */
    279 unsigned int data1:15; /**< data field one */
    280 unsigned int data2:15; /**< data field two */
    281 } asbits;
    282 int asint; /**< inference information as a single int value */
    283 } val;
    284};
    285typedef struct InferInfo INFERINFO;
    286
    287/** converts an integer into an inference information */
    288static
    290 int i /**< integer to convert */
    291 )
    292{
    293 INFERINFO inferinfo;
    294
    295 inferinfo.val.asint = i;
    296
    297 return inferinfo;
    298}
    299
    300/** converts an inference information into an int */
    301static
    303 INFERINFO inferinfo /**< inference information to convert */
    304 )
    305{
    306 return inferinfo.val.asint;
    307}
    308
    309/** rounds real to int and maps for large absolute values */
    310static
    312 SCIP* scip, /**< scip data structure */
    313 SCIP_Real real /**< double bound to convert */
    314 )
    315{
    316 int maxval;
    317
    319
    320 assert(maxval >= 0);
    321
    322 if( SCIPisInfinity(scip, real) || real > maxval )
    323 {
    324 return maxval;
    325 }
    326 if( SCIPisInfinity(scip, -real) || real < -maxval )
    327 {
    328 return -maxval;
    329 }
    331}
    332
    333/** returns the propagation rule stored in the inference information */
    334static
    336 INFERINFO inferinfo /**< inference information to convert */
    337 )
    338{
    339 return (PROPRULE) inferinfo.val.asbits.proprule;
    340}
    341
    342/** returns data field one of the inference information */
    343static
    345 INFERINFO inferinfo /**< inference information to convert */
    346 )
    347{
    348 return (int) inferinfo.val.asbits.data1;
    349}
    350
    351/** returns data field two of the inference information */
    352static
    354 INFERINFO inferinfo /**< inference information to convert */
    355 )
    356{
    357 return (int) inferinfo.val.asbits.data2;
    358}
    359
    360/** returns whether the inference information is valid */
    361static
    363 INFERINFO inferinfo /**< inference information to convert */
    364 )
    365{
    366 return (inferinfo.val.asint != 0);
    367}
    368
    369
    370/** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
    371static
    373 PROPRULE proprule, /**< propagation rule that deduced the value */
    374 int data1, /**< data field one */
    375 int data2 /**< data field two */
    376 )
    377{
    378 INFERINFO inferinfo;
    379
    380 /* check that the data members are in the range of the available bits */
    381 if( proprule == PROPRULE_0_INVALID || data1 < 0 || data1 >= (1<<15) || data2 < 0 || data2 >= (1<<15) )
    382 {
    383 inferinfo.val.asint = 0;
    384 assert(inferInfoGetProprule(inferinfo) == PROPRULE_0_INVALID);
    385 assert(inferInfoIsValid(inferinfo) == FALSE);
    386 }
    387 else
    388 {
    389 inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
    390 inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
    391 inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
    392 assert(inferInfoIsValid(inferinfo) == TRUE);
    393 }
    394
    395 return inferinfo;
    396}
    397
    398/**@} */
    399
    400/*
    401 * Local methods
    402 */
    403
    404/**@name Miscellaneous Methods
    405 *
    406 * @{
    407 */
    408
    409#ifndef NDEBUG
    410
    411/** compute the core of a job which lies in certain interval [begin, end) */
    412static
    414 int begin, /**< begin of the interval */
    415 int end, /**< end of the interval */
    416 int ect, /**< earliest completion time */
    417 int lst /**< latest start time */
    418 )
    419{
    420 int core;
    421
    422 core = MAX(0, MIN(end, ect) - MAX(lst, begin));
    423
    424 return core;
    425}
    426#else
    427#define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
    428#endif
    429
    430/** returns the implied earliest start time */ /*lint -e{715}*/
    431static
    433 SCIP* scip, /**< SCIP data structure */
    434 SCIP_VAR* var, /**< variable for which the implied est should be returned */
    435 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
    436 int* est /**< pointer to store the implied earliest start time */
    437 )
    438{ /*lint --e{715}*/
    439#ifdef SCIP_DISABLED_CODE
    440 /* there is a bug below */
    441 SCIP_VAR** vbdvars;
    442 SCIP_VAR* vbdvar;
    443 SCIP_Real* vbdcoefs;
    444 SCIP_Real* vbdconsts;
    445 void* image;
    446 int nvbdvars;
    447 int v;
    448#endif
    449
    451
    452#ifdef SCIP_DISABLED_CODE
    453 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
    454
    455 nvbdvars = SCIPvarGetNVlbs(var);
    456 vbdvars = SCIPvarGetVlbVars(var);
    457 vbdcoefs = SCIPvarGetVlbCoefs(var);
    458 vbdconsts = SCIPvarGetVlbConstants(var);
    459
    460 for( v = 0; v < nvbdvars; ++v )
    461 {
    462 vbdvar = vbdvars[v];
    463 assert(vbdvar != NULL);
    464
    465 image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
    466
    467 if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
    468 {
    469 int duration;
    470 int vbdconst;
    471
    472 duration = (int)(size_t)image;
    473 vbdconst = boundedConvertRealToInt(scip, vbdconsts[v]);
    474
    475 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
    477 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
    478
    479 if( duration >= vbdconst )
    480 {
    481 int impliedest;
    482
    483 impliedest = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
    484
    485 if( (*est) < impliedest )
    486 {
    487 (*est) = impliedest;
    488
    489 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
    490 }
    491 }
    492 }
    493 }
    494#endif
    495
    496 return SCIP_OKAY;
    497}
    498
    499/** returns the implied latest completion time */ /*lint -e{715}*/
    500static
    502 SCIP* scip, /**< SCIP data structure */
    503 SCIP_VAR* var, /**< variable for which the implied est should be returned */
    504 int duration, /**< duration of the given job */
    505 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
    506 int* lct /**< pointer to store the implied latest completion time */
    507 )
    508{ /*lint --e{715}*/
    509#ifdef SCIP_DISABLED_CODE
    510 /* there is a bug below */
    511 SCIP_VAR** vbdvars;
    512 SCIP_VAR* vbdvar;
    513 SCIP_Real* vbdcoefs;
    514 SCIP_Real* vbdconsts;
    515 int nvbdvars;
    516 int v;
    517#endif
    518
    519 (*lct) = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
    520
    521#ifdef SCIP_DISABLED_CODE
    522 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
    523
    524 nvbdvars = SCIPvarGetNVubs(var);
    525 vbdvars = SCIPvarGetVubVars(var);
    526 vbdcoefs = SCIPvarGetVubCoefs(var);
    527 vbdconsts = SCIPvarGetVubConstants(var);
    528
    529 for( v = 0; v < nvbdvars; ++v )
    530 {
    531 vbdvar = vbdvars[v];
    532 assert(vbdvar != NULL);
    533
    534 if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
    535 {
    536 int vbdconst;
    537
    538 vbdconst = boundedConvertRealToInt(scip, -vbdconsts[v]);
    539
    540 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
    542 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
    543
    544 if( duration >= -vbdconst )
    545 {
    546 int impliedlct;
    547
    548 impliedlct = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
    549
    550 if( (*lct) > impliedlct )
    551 {
    552 (*lct) = impliedlct;
    553
    554 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
    555 }
    556 }
    557 }
    558 }
    559#endif
    560
    561 return SCIP_OKAY;
    562}
    563
    564/** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
    565static
    567 SCIP* scip, /**< SCIP data structure */
    568 SCIP_CONSDATA* consdata, /**< constraint data */
    569 SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
    570 int** coefs, /**< pointer to store the coefficients */
    571 int* nvars, /**< number if collect binary variables */
    572 int* startindices, /**< permutation with rspect to the start times */
    573 int curtime, /**< current point in time */
    574 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    575 int nfinished /**< number of jobs that finished before curtime or at curtime */
    576 )
    577{
    578 int nrowvars;
    579 int startindex;
    580 int size;
    581
    582 size = 10;
    583 nrowvars = 0;
    584 startindex = nstarted - 1;
    585
    586 SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
    587 SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
    588
    589 /* search for the (nstarted - nfinished) jobs which are active at curtime */
    590 while( nstarted - nfinished > nrowvars )
    591 {
    592 SCIP_VAR* var;
    593 int endtime;
    594 int duration;
    595 int demand;
    596 int varidx;
    597
    598 /* collect job information */
    599 varidx = startindices[startindex];
    600 assert(varidx >= 0 && varidx < consdata->nvars);
    601
    602 var = consdata->vars[varidx];
    603 duration = consdata->durations[varidx];
    604 demand = consdata->demands[varidx];
    605 assert(var != NULL);
    606
    607 endtime = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
    608
    609 /* check the end time of this job is larger than the curtime; in this case the job is still running */
    610 if( endtime > curtime )
    611 {
    612 SCIP_VAR** binvars;
    613 SCIP_Real* vals;
    614 int nbinvars;
    615 int start;
    616 int end;
    617 int b;
    618
    619 /* check if the linking constraints exists */
    620 assert(SCIPexistsConsLinking(scip, var));
    621 assert(SCIPgetConsLinking(scip, var) != NULL);
    622 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
    623
    624 /* collect linking constraint information */
    625 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
    626 vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
    627
    628 start = curtime - duration + 1;
    629 end = MIN(curtime, endtime - duration);
    630
    631 for( b = 0; b < nbinvars; ++b )
    632 {
    633 if( vals[b] < start )
    634 continue;
    635
    636 if( vals[b] > end )
    637 break;
    638
    639 assert(binvars[b] != NULL);
    640
    641 /* ensure array proper array size */
    642 if( size == *nvars )
    643 {
    644 size *= 2;
    645 SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
    646 SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
    647 }
    648
    649 (*vars)[*nvars] = binvars[b];
    650 (*coefs)[*nvars] = demand;
    651 (*nvars)++;
    652 }
    653 nrowvars++;
    654 }
    655
    656 startindex--;
    657 }
    658
    659 return SCIP_OKAY;
    660}
    661
    662/** collect all integer variable which belong to jobs which can run at the point of interest */
    663static
    665 SCIP* scip, /**< SCIP data structure */
    666 SCIP_CONSDATA* consdata, /**< constraint data */
    667 SCIP_VAR*** activevars, /**< jobs that are currently running */
    668 int* startindices, /**< permutation with rspect to the start times */
    669 int curtime, /**< current point in time */
    670 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    671 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    672 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
    673 int* lhs /**< lhs for the new row sum of lbs + minoffset */
    674 )
    675{
    676 SCIP_VAR* var;
    677 int startindex;
    678 int endtime;
    679 int duration;
    680 int starttime;
    681
    682 int varidx;
    683 int sumofstarts;
    684 int mindelta;
    685 int counter;
    686
    687 assert(curtime >= consdata->hmin);
    688 assert(curtime < consdata->hmax);
    689
    690 counter = 0;
    691 sumofstarts = 0;
    692
    693 mindelta = INT_MAX;
    694
    695 startindex = nstarted - 1;
    696
    697 /* search for the (nstarted - nfinished) jobs which are active at curtime */
    698 while( nstarted - nfinished > counter )
    699 {
    700 assert(startindex >= 0);
    701
    702 /* collect job information */
    703 varidx = startindices[startindex];
    704 assert(varidx >= 0 && varidx < consdata->nvars);
    705
    706 var = consdata->vars[varidx];
    707 duration = consdata->durations[varidx];
    708 assert(duration > 0);
    709 assert(var != NULL);
    710
    711 if( lower )
    713 else
    715
    716 endtime = MIN(starttime + duration, consdata->hmax);
    717
    718 /* check the end time of this job is larger than the curtime; in this case the job is still running */
    719 if( endtime > curtime )
    720 {
    721 (*activevars)[counter] = var;
    722 sumofstarts += starttime;
    723 mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
    724 counter++;
    725 }
    726
    727 startindex--;
    728 }
    729
    730 assert(mindelta > 0);
    731 *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
    732
    733 return SCIP_OKAY;
    734}
    735
    736/** initialize the sorted event point arrays */
    737static
    739 SCIP* scip, /**< SCIP data structure */
    740 int nvars, /**< number of start time variables (activities) */
    741 SCIP_VAR** vars, /**< array of start time variables */
    742 int* durations, /**< array of durations per start time variable */
    743 int* starttimes, /**< array to store sorted start events */
    744 int* endtimes, /**< array to store sorted end events */
    745 int* startindices, /**< permutation with rspect to the start times */
    746 int* endindices, /**< permutation with rspect to the end times */
    747 SCIP_Bool local /**< shall local bounds be used */
    748 )
    749{
    750 SCIP_VAR* var;
    751 int j;
    752
    753 assert(vars != NULL || nvars == 0);
    754
    755 /* assign variables, start and endpoints to arrays */
    756 for ( j = 0; j < nvars; ++j )
    757 {
    758 assert(vars != NULL);
    759
    760 var = vars[j];
    761 assert(var != NULL);
    762
    763 if( local )
    764 starttimes[j] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var));
    765 else
    766 starttimes[j] = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var));
    767
    768 startindices[j] = j;
    769
    770 if( local )
    771 endtimes[j] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
    772 else
    773 endtimes[j] = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
    774
    775 endindices[j] = j;
    776 }
    777
    778 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
    779 SCIPsortIntInt(starttimes, startindices, j);
    780 SCIPsortIntInt(endtimes, endindices, j);
    781}
    782
    783/** initialize the sorted event point arrays w.r.t. the given primal solutions */
    784static
    786 SCIP* scip, /**< SCIP data structure */
    787 SCIP_SOL* sol, /**< solution */
    788 int nvars, /**< number of start time variables (activities) */
    789 SCIP_VAR** vars, /**< array of start time variables */
    790 int* durations, /**< array of durations per start time variable */
    791 int* starttimes, /**< array to store sorted start events */
    792 int* endtimes, /**< array to store sorted end events */
    793 int* startindices, /**< permutation with rspect to the start times */
    794 int* endindices /**< permutation with rspect to the end times */
    795 )
    796{
    797 SCIP_VAR* var;
    798 int j;
    799
    800 assert(vars != NULL || nvars == 0);
    801
    802 /* assign variables, start and endpoints to arrays */
    803 for ( j = 0; j < nvars; ++j )
    804 {
    805 assert(vars != NULL);
    806
    807 var = vars[j];
    808 assert(var != NULL);
    809
    810 starttimes[j] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
    811 startindices[j] = j;
    812
    813 endtimes[j] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
    814 endindices[j] = j;
    815 }
    816
    817 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
    818 SCIPsortIntInt(starttimes, startindices, j);
    819 SCIPsortIntInt(endtimes, endindices, j);
    820}
    821
    822/** initialize the sorted event point arrays
    823 *
    824 * @todo Check the separation process!
    825 */
    826static
    828 SCIP* scip, /**< SCIP data structure */
    829 SCIP_CONSDATA* consdata, /**< constraint data */
    830 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    831 int* starttimes, /**< array to store sorted start events */
    832 int* endtimes, /**< array to store sorted end events */
    833 int* startindices, /**< permutation with rspect to the start times */
    834 int* endindices, /**< permutation with rspect to the end times */
    835 int* nvars, /**< number of variables that are integral */
    836 SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
    837 )
    838{
    839 SCIP_VAR* var;
    840 int tmpnvars;
    841 int j;
    842
    843 tmpnvars = consdata->nvars;
    844 *nvars = 0;
    845
    846 /* assign variables, start and endpoints to arrays */
    847 for ( j = 0; j < tmpnvars; ++j )
    848 {
    849 var = consdata->vars[j];
    850 assert(var != NULL);
    851 assert(consdata->durations[j] > 0);
    852 assert(consdata->demands[j] > 0);
    853
    854 if( lower )
    855 {
    856 /* only consider jobs that are at their lower or upper bound */
    857 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
    858 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
    859 continue;
    860
    861 starttimes[*nvars] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
    862 startindices[*nvars] = j;
    863
    864 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
    865 endindices[*nvars] = j;
    866
    867 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
    868 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
    869 consdata->durations[j],
    870 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
    871 consdata->demands[startindices[*nvars]]);
    872
    873 (*nvars)++;
    874 }
    875 else
    876 {
    877 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
    878 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
    879 continue;
    880
    881 starttimes[*nvars] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
    882 startindices[*nvars] = j;
    883
    884 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
    885 endindices[*nvars] = j;
    886
    887 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
    888 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
    889 consdata->durations[j],
    890 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
    891 consdata->demands[startindices[*nvars]]);
    892
    893 (*nvars)++;
    894 }
    895 }
    896
    897 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
    898 SCIPsortIntInt(starttimes, startindices, *nvars);
    899 SCIPsortIntInt(endtimes, endindices, *nvars);
    900
    901#ifdef SCIP_DEBUG
    902 SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
    903
    904 for ( j = 0; j < *nvars; ++j )
    905 {
    906 SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
    907 startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
    908 consdata->demands[startindices[j]]);
    909 }
    910
    911 for ( j = 0; j < *nvars; ++j )
    912 {
    913 SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
    914 consdata->demands[endindices[j]]);
    915 }
    916#endif
    917}
    918
    919#ifdef SCIP_STATISTIC
    920/** this method checks for relevant intervals for energetic reasoning */
    921static
    922SCIP_RETCODE computeRelevantEnergyIntervals(
    923 SCIP* scip, /**< SCIP data structure */
    924 int nvars, /**< number of start time variables (activities) */
    925 SCIP_VAR** vars, /**< array of start time variables */
    926 int* durations, /**< array of durations */
    927 int* demands, /**< array of demands */
    928 int capacity, /**< cumulative capacity */
    929 int hmin, /**< left bound of time axis to be considered (including hmin) */
    930 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    931 int** timepoints, /**< array to store relevant points in time */
    932 SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
    933 int* ntimepoints, /**< pointer to store the number of timepoints */
    934 int* maxdemand, /**< pointer to store maximum over all demands */
    935 SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
    936 )
    937{
    938 int* starttimes; /* stores when each job is starting */
    939 int* endtimes; /* stores when each job ends */
    940 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    941 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    942
    943 SCIP_Real totaldemand;
    944 int curtime; /* point in time which we are just checking */
    945 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    946
    947 int j;
    948
    949 assert( scip != NULL );
    950 assert(durations != NULL);
    951 assert(demands != NULL);
    952 assert(capacity >= 0);
    953
    954 /* if no activities are associated with this cumulative then this constraint is redundant */
    955 if( nvars == 0 )
    956 return SCIP_OKAY;
    957
    958 assert(vars != NULL);
    959
    960 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    961 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    962 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    963 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    964
    965 /* create event point arrays */
    966 createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
    967
    968 endindex = 0;
    969 totaldemand = 0.0;
    970
    971 *ntimepoints = 0;
    972 (*timepoints)[0] = starttimes[0];
    973 (*cumulativedemands)[0] = 0;
    974 *maxdemand = 0;
    975
    976 /* check each startpoint of a job whether the capacity is kept or not */
    977 for( j = 0; j < nvars; ++j )
    978 {
    979 int lct;
    980 int idx;
    981
    982 curtime = starttimes[j];
    983
    984 if( curtime >= hmax )
    985 break;
    986
    987 /* free all capacity usages of jobs the are no longer running */
    988 while( endindex < nvars && endtimes[endindex] <= curtime )
    989 {
    990 int est;
    991
    992 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
    993 {
    994 (*ntimepoints)++;
    995 (*timepoints)[*ntimepoints] = endtimes[endindex];
    996 (*cumulativedemands)[*ntimepoints] = 0;
    997 }
    998
    999 idx = endindices[endindex];
    1001 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
    1002 endindex++;
    1003
    1004 (*cumulativedemands)[*ntimepoints] = totaldemand;
    1005 }
    1006
    1007 idx = startindices[j];
    1008 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
    1009 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
    1010
    1011 if( (*timepoints)[*ntimepoints] < curtime )
    1012 {
    1013 (*ntimepoints)++;
    1014 (*timepoints)[*ntimepoints] = curtime;
    1015 (*cumulativedemands)[*ntimepoints] = 0;
    1016 }
    1017
    1018 (*cumulativedemands)[*ntimepoints] = totaldemand;
    1019
    1020 /* add the relative capacity requirements for all job which start at the curtime */
    1021 while( j+1 < nvars && starttimes[j+1] == curtime )
    1022 {
    1023 ++j;
    1024 idx = startindices[j];
    1025 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
    1026 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
    1027
    1028 (*cumulativedemands)[*ntimepoints] = totaldemand;
    1029 }
    1030 } /*lint --e{850}*/
    1031
    1032 /* free all capacity usages of jobs that are no longer running */
    1033 while( endindex < nvars/* && endtimes[endindex] < hmax*/)
    1034 {
    1035 int est;
    1036 int idx;
    1037
    1038 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
    1039 {
    1040 (*ntimepoints)++;
    1041 (*timepoints)[*ntimepoints] = endtimes[endindex];
    1042 (*cumulativedemands)[*ntimepoints] = 0;
    1043 }
    1044
    1045 idx = endindices[endindex];
    1047 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
    1048 (*cumulativedemands)[*ntimepoints] = totaldemand;
    1049
    1050 ++endindex;
    1051 }
    1052
    1053 (*ntimepoints)++;
    1054 /* compute minimum free capacity */
    1055 (*minfreecapacity) = INT_MAX;
    1056 for( j = 0; j < *ntimepoints; ++j )
    1057 {
    1058 if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
    1059 *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
    1060 }
    1061
    1062 /* free buffer arrays */
    1063 SCIPfreeBufferArray(scip, &endindices);
    1064 SCIPfreeBufferArray(scip, &startindices);
    1065 SCIPfreeBufferArray(scip, &endtimes);
    1066 SCIPfreeBufferArray(scip, &starttimes);
    1067
    1068 return SCIP_OKAY;
    1069}
    1070
    1071/** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
    1072static
    1073SCIP_RETCODE evaluateCumulativeness(
    1074 SCIP* scip, /**< pointer to scip */
    1075 SCIP_CONS* cons /**< cumulative constraint */
    1076 )
    1077{
    1078 SCIP_CONSDATA* consdata;
    1079 int nvars;
    1080 int v;
    1081 int capacity;
    1082
    1083 /* output values: */
    1084 SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
    1085 SCIP_Real cumfactor1;
    1086 SCIP_Real resstrength1; /* overall strength */
    1087 SCIP_Real resstrength2; /* timepoint wise maximum */
    1088
    1089 /* helpful variables: */
    1090 SCIP_Real globalpeak;
    1091 SCIP_Real globalmaxdemand;
    1092
    1093 /* get constraint data structure */
    1094 consdata = SCIPconsGetData(cons);
    1095 assert(consdata != NULL);
    1096
    1097 nvars = consdata->nvars;
    1098 capacity = consdata->capacity;
    1099 globalpeak = 0.0;
    1100 globalmaxdemand = 0.0;
    1101
    1102 disjfactor2 = 0.0;
    1103 cumfactor1 = 0.0;
    1104 resstrength2 = 0.0;
    1105
    1106 /* check each starting time (==each job, but inefficient) */
    1107 for( v = 0; v < nvars; ++v )
    1108 {
    1109 SCIP_Real peak;
    1110 SCIP_Real maxdemand;
    1111 SCIP_Real deltademand;
    1112 int ndemands;
    1113 int nlarge;
    1114
    1115 int timepoint;
    1116 int j;
    1117 timepoint = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
    1118 peak = consdata->demands[v];
    1119 ndemands = 1;
    1120 maxdemand = 0;
    1121 nlarge = 0;
    1122
    1123 if( consdata->demands[v] > capacity / 3 )
    1124 nlarge++;
    1125
    1126 for( j = 0; j < nvars; ++j )
    1127 {
    1128 int lb;
    1129
    1130 if( j == v )
    1131 continue;
    1132
    1133 maxdemand = 0.0;
    1134 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
    1135
    1136 if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
    1137 {
    1138 peak += consdata->demands[j];
    1139 ndemands++;
    1140
    1141 if( consdata->demands[j] > consdata->capacity / 3 )
    1142 nlarge++;
    1143 }
    1144 }
    1145
    1146 deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
    1147 globalpeak = MAX(globalpeak, peak);
    1148 globalmaxdemand = MAX(globalmaxdemand, maxdemand);
    1149
    1150 if( peak > capacity )
    1151 {
    1152 disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
    1153 cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
    1154 resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
    1155 }
    1156 }
    1157
    1158 resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
    1159
    1160 consdata->maxpeak = boundedConvertRealToInt(scip, globalpeak);
    1161 consdata->disjfactor2 = disjfactor2;
    1162 consdata->cumfactor1 = cumfactor1;
    1163 consdata->resstrength2 = resstrength2;
    1164 consdata->resstrength1 = resstrength1;
    1165
    1166 /* get estimated res strength */
    1167 {
    1168 int* timepoints;
    1169 SCIP_Real* estimateddemands;
    1170 int ntimepoints;
    1171 int maxdemand;
    1172 SCIP_Real minfreecapacity;
    1173
    1174 SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
    1175 SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
    1176
    1177 ntimepoints = 0;
    1178 minfreecapacity = INT_MAX;
    1179
    1180 SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
    1181 consdata->durations, consdata->demands,
    1182 capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
    1183 &ntimepoints, &maxdemand, &minfreecapacity) );
    1184
    1185 /* free buffer arrays */
    1186 SCIPfreeBufferArray(scip, &estimateddemands);
    1187 SCIPfreeBufferArray(scip, &timepoints);
    1188
    1189 consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
    1190 }
    1191
    1192 SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
    1193 SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
    1194 consdata->estimatedstrength);
    1195
    1196 return SCIP_OKAY;
    1197}
    1198#endif
    1199
    1200/** gets the active variables together with the constant */
    1201static
    1203 SCIP* scip, /**< SCIP data structure */
    1204 SCIP_VAR** var, /**< pointer to store the active variable */
    1205 int* scalar, /**< pointer to store the scalar */
    1206 int* constant /**< pointer to store the constant */
    1207 )
    1208{
    1209 if( !SCIPvarIsActive(*var) )
    1210 {
    1211 SCIP_Real realscalar;
    1212 SCIP_Real realconstant;
    1213
    1214 realscalar = 1.0;
    1215 realconstant = 0.0;
    1216
    1218
    1219 /* transform variable to active variable */
    1220 SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
    1221 assert(!SCIPisZero(scip, realscalar));
    1222 assert(SCIPvarIsActive(*var));
    1223
    1224 if( realconstant < 0.0 )
    1225 (*constant) = -boundedConvertRealToInt(scip, -realconstant);
    1226 else
    1227 (*constant) = boundedConvertRealToInt(scip, realconstant);
    1228
    1229 if( realscalar < 0.0 )
    1230 (*scalar) = -boundedConvertRealToInt(scip, -realscalar);
    1231 else
    1232 (*scalar) = boundedConvertRealToInt(scip, realscalar);
    1233 }
    1234 else
    1235 {
    1236 (*scalar) = 1;
    1237 (*constant) = 0;
    1238 }
    1239
    1240 assert(*scalar != 0);
    1241
    1242 return SCIP_OKAY;
    1243}
    1244
    1245/** computes the total energy of all jobs */
    1246static
    1248 int* durations, /**< array of job durations */
    1249 int* demands, /**< array of job demands */
    1250 int njobs /**< number of jobs */
    1251 )
    1252{
    1253 SCIP_Longint energy;
    1254 int j;
    1255
    1256 energy = 0;
    1257
    1258 for( j = 0; j < njobs; ++j )
    1259 energy += (SCIP_Longint) durations[j] * demands[j];
    1260
    1261 return energy;
    1262}
    1263
    1264/**@} */
    1265
    1266/**@name Default method to solve a cumulative condition
    1267 *
    1268 * @{
    1269 */
    1270
    1271/** setup and solve subscip to solve single cumulative condition */
    1272static
    1274 SCIP* subscip, /**< subscip data structure */
    1275 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
    1276 int* durations, /**< array of durations */
    1277 int* demands, /**< array of demands */
    1278 int njobs, /**< number of jobs (activities) */
    1279 int capacity, /**< cumulative capacity */
    1280 int hmin, /**< left bound of time axis to be considered (including hmin) */
    1281 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    1282 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
    1283 SCIP_Real timelimit, /**< time limit for solving in seconds */
    1284 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
    1285 SCIP_Real* ests, /**< array of earliest start times for each job */
    1286 SCIP_Real* lsts, /**< array of latest start times for each job */
    1287 SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
    1288 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
    1289 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
    1290 SCIP_Bool* error /**< pointer to store if an error occurred */
    1291 )
    1292{
    1293 SCIP_VAR** subvars;
    1294 SCIP_CONS* cons;
    1295
    1296 char name[SCIP_MAXSTRLEN];
    1297 int v;
    1298 SCIP_RETCODE retcode;
    1299
    1300 assert(subscip != NULL);
    1301
    1302 /* copy all plugins */
    1304
    1305 /* create the subproblem */
    1306 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
    1307
    1308 SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
    1309
    1310 /* create for each job a start time variable */
    1311 for( v = 0; v < njobs; ++v )
    1312 {
    1313 SCIP_Real objval;
    1314
    1315 /* construct variable name */
    1316 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
    1317
    1318 if( objvals == NULL )
    1319 objval = 0.0;
    1320 else
    1321 objval = objvals[v];
    1322
    1323 SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
    1324 SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
    1325 }
    1326
    1327 /* create cumulative constraint */
    1328 SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
    1329 njobs, subvars, durations, demands, capacity) );
    1330
    1331 /* set effective horizon */
    1332 SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
    1333 SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
    1334
    1335 /* add cumulative constraint */
    1336 SCIP_CALL( SCIPaddCons(subscip, cons) );
    1337 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
    1338
    1339 /* set CP solver settings
    1340 *
    1341 * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
    1342 * time limit.
    1343 */
    1345
    1346 /* do not abort subproblem on CTRL-C */
    1347 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
    1348
    1349 /* disable output to console */
    1350 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
    1351
    1352 /* set limits for the subproblem */
    1353 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
    1354 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
    1355 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
    1356
    1357 /* forbid recursive call of heuristics and separators solving subMIPs */
    1358 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
    1359
    1360 /* solve single cumulative constraint by branch and bound */
    1361 retcode = SCIPsolve(subscip);
    1362
    1363 if( retcode != SCIP_OKAY )
    1364 (*error) = TRUE;
    1365 else
    1366 {
    1367 SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
    1368
    1369 /* evaluated solution status */
    1370 switch( SCIPgetStatus(subscip) )
    1371 {
    1374 (*infeasible) = TRUE;
    1375 (*solved) = TRUE;
    1376 break;
    1378 (*unbounded) = TRUE;
    1379 (*solved) = TRUE;
    1380 break;
    1382 {
    1383 SCIP_SOL* sol;
    1384 SCIP_Real solval;
    1385
    1386 sol = SCIPgetBestSol(subscip);
    1387 assert(sol != NULL);
    1388
    1389 for( v = 0; v < njobs; ++v )
    1390 {
    1391 solval = SCIPgetSolVal(subscip, sol, subvars[v]);
    1392
    1393 ests[v] = solval;
    1394 lsts[v] = solval;
    1395 }
    1396 (*solved) = TRUE;
    1397 break;
    1398 }
    1405 /* transfer the global bound changes */
    1406 for( v = 0; v < njobs; ++v )
    1407 {
    1408 ests[v] = SCIPvarGetLbGlobal(subvars[v]);
    1409 lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
    1410 }
    1411 (*solved) = FALSE;
    1412 break;
    1413
    1422 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
    1423 return SCIP_INVALIDDATA;
    1424 }
    1425 }
    1426
    1427 /* release all variables */
    1428 for( v = 0; v < njobs; ++v )
    1429 {
    1430 SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
    1431 }
    1432
    1433 SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
    1434
    1435 return SCIP_OKAY;
    1436}
    1437
    1438/** solve single cumulative condition using SCIP and a single cumulative constraint */
    1439static
    1440SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
    1441{
    1442 SCIP* subscip;
    1443
    1444 SCIP_RETCODE retcode;
    1445
    1446 assert(njobs > 0);
    1447
    1448 (*solved) = FALSE;
    1449 (*infeasible) = FALSE;
    1450 (*unbounded) = FALSE;
    1451 (*error) = FALSE;
    1452
    1453 SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
    1454
    1455 /* initialize the sub-problem */
    1456 SCIP_CALL( SCIPcreate(&subscip) );
    1457
    1458 /* create and solve the subproblem. catch possible errors */
    1459 retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
    1460 njobs, capacity, hmin, hmax,
    1461 maxnodes, timelimit, memorylimit,
    1462 ests, lsts,
    1463 infeasible, unbounded, solved, error);
    1464
    1465 /* free the subscip in any case */
    1466 SCIP_CALL( SCIPfree(&subscip) );
    1467
    1468 SCIP_CALL( retcode );
    1469
    1470 return SCIP_OKAY;
    1471}
    1472
    1473#ifdef SCIP_DISABLED_CODE
    1474/* The following code should work, but is currently not used. */
    1475
    1476/** solve single cumulative condition using SCIP and the time indexed formulation */
    1477static
    1478SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
    1479{
    1480 SCIP* subscip;
    1481 SCIP_VAR*** binvars;
    1482 SCIP_RETCODE retcode;
    1483 char name[SCIP_MAXSTRLEN];
    1484 int minest;
    1485 int maxlct;
    1486 int t;
    1487 int v;
    1488
    1489 assert(njobs > 0);
    1490
    1491 (*solved) = FALSE;
    1492 (*infeasible) = FALSE;
    1493 (*unbounded) = FALSE;
    1494 (*error) = FALSE;
    1495
    1496 SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
    1497
    1498 /* initialize the sub-problem */
    1499 SCIP_CALL( SCIPcreate(&subscip) );
    1500
    1501 /* copy all plugins */
    1503
    1504 /* create the subproblem */
    1505 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
    1506
    1507 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
    1508
    1509 minest = INT_MAX;
    1510 maxlct = INT_MIN;
    1511
    1512 /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
    1513 * partitioning constrain which forces that job starts
    1514 */
    1515 for( v = 0; v < njobs; ++v )
    1516 {
    1517 SCIP_CONS* cons;
    1518 SCIP_Real objval;
    1519 int timeinterval;
    1520 int est;
    1521 int lst;
    1522
    1523 if( objvals == NULL )
    1524 objval = 0.0;
    1525 else
    1526 objval = objvals[v];
    1527
    1528 est = ests[v];
    1529 lst = lsts[v];
    1530
    1531 /* compute number of possible start points */
    1532 timeinterval = lst - est + 1;
    1533 assert(timeinterval > 0);
    1534
    1535 /* compute the smallest earliest start time and largest latest completion time */
    1536 minest = MIN(minest, est);
    1537 maxlct = MAX(maxlct, lst + durations[v]);
    1538
    1539 /* construct constraint name */
    1540 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
    1541
    1542 SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
    1543
    1544 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
    1545
    1546 for( t = 0; t < timeinterval; ++t )
    1547 {
    1548 SCIP_VAR* binvar;
    1549
    1550 /* construct varibale name */
    1551 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
    1552
    1553 SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
    1554 SCIP_CALL( SCIPaddVar(subscip, binvar) );
    1555
    1556 /* add binary varibale to the set partitioning constraint which ensures that the job is started */
    1557 SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
    1558
    1559 binvars[v][t] = binvar;
    1560 }
    1561
    1562 /* add and release the set partitioning constraint */
    1563 SCIP_CALL( SCIPaddCons(subscip, cons) );
    1564 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
    1565 }
    1566
    1567 /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
    1568 hmin = MAX(hmin, minest);
    1569 hmax = MIN(hmax, maxlct);
    1570 assert(hmin > INT_MIN);
    1571 assert(hmax < INT_MAX);
    1572 assert(hmin < hmax);
    1573
    1574 /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
    1575 for( t = hmin; t < hmax; ++t )
    1576 {
    1577 SCIP_CONS* cons;
    1578
    1579 /* construct constraint name */
    1580 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
    1581
    1582 /* create an empty knapsack constraint */
    1583 SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
    1584
    1585 /* add all jobs which potentially can be processed at that time point */
    1586 for( v = 0; v < njobs; ++v )
    1587 {
    1588 int duration;
    1589 int demand;
    1590 int start;
    1591 int end;
    1592 int est;
    1593 int lst;
    1594 int k;
    1595
    1596 est = ests[v];
    1597 lst = lsts[v] ;
    1598
    1599 duration = durations[v];
    1600 assert(duration > 0);
    1601
    1602 /* check if the varibale is processed potentially at time point t */
    1603 if( t < est || t >= lst + duration )
    1604 continue;
    1605
    1606 demand = demands[v];
    1607 assert(demand >= 0);
    1608
    1609 start = MAX(t - duration + 1, est);
    1610 end = MIN(t, lst);
    1611
    1612 assert(start <= end);
    1613
    1614 for( k = start; k <= end; ++k )
    1615 {
    1616 assert(binvars[v][k] != NULL);
    1617 SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
    1618 }
    1619 }
    1620
    1621 /* add and release the knapsack constraint */
    1622 SCIP_CALL( SCIPaddCons(subscip, cons) );
    1623 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
    1624 }
    1625
    1626 /* do not abort subproblem on CTRL-C */
    1627 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
    1628
    1629 /* disable output to console */
    1630 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
    1631
    1632 /* set limits for the subproblem */
    1633 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
    1634 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
    1635 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
    1636
    1637 /* solve single cumulative constraint by branch and bound */
    1638 retcode = SCIPsolve(subscip);
    1639
    1640 if( retcode != SCIP_OKAY )
    1641 (*error) = TRUE;
    1642 else
    1643 {
    1644 SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
    1645
    1646 /* evaluated solution status */
    1647 switch( SCIPgetStatus(subscip) )
    1648 {
    1651 (*infeasible) = TRUE;
    1652 (*solved) = TRUE;
    1653 break;
    1655 (*unbounded) = TRUE;
    1656 (*solved) = TRUE;
    1657 break;
    1659 {
    1660 SCIP_SOL* sol;
    1661
    1662 sol = SCIPgetBestSol(subscip);
    1663 assert(sol != NULL);
    1664
    1665 for( v = 0; v < njobs; ++v )
    1666 {
    1667 int timeinterval;
    1668 int est;
    1669 int lst;
    1670
    1671 est = ests[v];
    1672 lst = lsts[v];
    1673
    1674 /* compute number of possible start points */
    1675 timeinterval = lst - est + 1;
    1676
    1677 /* check which binary varibale is set to one */
    1678 for( t = 0; t < timeinterval; ++t )
    1679 {
    1680 if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
    1681 {
    1682 ests[v] = est + t;
    1683 lsts[v] = est + t;
    1684 break;
    1685 }
    1686 }
    1687 }
    1688
    1689 (*solved) = TRUE;
    1690 break;
    1691 }
    1697 /* transfer the global bound changes */
    1698 for( v = 0; v < njobs; ++v )
    1699 {
    1700 int timeinterval;
    1701 int est;
    1702 int lst;
    1703
    1704 est = ests[v];
    1705 lst = lsts[v];
    1706
    1707 /* compute number of possible start points */
    1708 timeinterval = lst - est + 1;
    1709
    1710 /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
    1711 for( t = 0; t < timeinterval; ++t )
    1712 {
    1713 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
    1714 {
    1715 ests[v] = est + t;
    1716 break;
    1717 }
    1718 }
    1719
    1720 /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
    1721 for( t = timeinterval - 1; t >= 0; --t )
    1722 {
    1723 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
    1724 {
    1725 lsts[v] = est + t;
    1726 break;
    1727 }
    1728 }
    1729 }
    1730 (*solved) = FALSE;
    1731 break;
    1732
    1738 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
    1739 return SCIP_INVALIDDATA;
    1740 }
    1741 }
    1742
    1743 /* release all variables */
    1744 for( v = 0; v < njobs; ++v )
    1745 {
    1746 int timeinterval;
    1747 int est;
    1748 int lst;
    1749
    1750 est = ests[v];
    1751 lst = lsts[v];
    1752
    1753 /* compute number of possible start points */
    1754 timeinterval = lst - est + 1;
    1755
    1756 for( t = 0; t < timeinterval; ++t )
    1757 {
    1758 SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
    1759 }
    1760 SCIPfreeBufferArray(subscip, &binvars[v]);
    1761 }
    1762
    1763 SCIPfreeBufferArray(subscip, &binvars);
    1764
    1765 SCIP_CALL( SCIPfree(&subscip) );
    1766
    1767 return SCIP_OKAY;
    1768}
    1769#endif
    1770
    1771/**@} */
    1772
    1773/**@name Constraint handler data
    1774 *
    1775 * Method used to create and free the constraint handler data when including and removing the cumulative constraint
    1776 * handler.
    1777 *
    1778 * @{
    1779 */
    1780
    1781/** creates constaint handler data for cumulative constraint handler */
    1782static
    1784 SCIP* scip, /**< SCIP data structure */
    1785 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
    1786 SCIP_EVENTHDLR* eventhdlr /**< event handler */
    1787 )
    1788{
    1789 /* create precedence constraint handler data */
    1790 assert(scip != NULL);
    1791 assert(conshdlrdata != NULL);
    1792 assert(eventhdlr != NULL);
    1793
    1794 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
    1795
    1796 /* set event handler for checking if bounds of start time variables are tighten */
    1797 (*conshdlrdata)->eventhdlr = eventhdlr;
    1798
    1799 /* set default methed for solving single cumulative conditions using SCIP and a CP model */
    1800 (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
    1801
    1802#ifdef SCIP_STATISTIC
    1803 (*conshdlrdata)->nlbtimetable = 0;
    1804 (*conshdlrdata)->nubtimetable = 0;
    1805 (*conshdlrdata)->ncutofftimetable = 0;
    1806 (*conshdlrdata)->nlbedgefinder = 0;
    1807 (*conshdlrdata)->nubedgefinder = 0;
    1808 (*conshdlrdata)->ncutoffedgefinder = 0;
    1809 (*conshdlrdata)->ncutoffoverload = 0;
    1810 (*conshdlrdata)->ncutoffoverloadTTEF = 0;
    1811
    1812 (*conshdlrdata)->nirrelevantjobs = 0;
    1813 (*conshdlrdata)->nalwaysruns = 0;
    1814 (*conshdlrdata)->nremovedlocks = 0;
    1815 (*conshdlrdata)->ndualfixs = 0;
    1816 (*conshdlrdata)->ndecomps = 0;
    1817 (*conshdlrdata)->ndualbranchs = 0;
    1818 (*conshdlrdata)->nallconsdualfixs = 0;
    1819 (*conshdlrdata)->naddedvarbounds = 0;
    1820 (*conshdlrdata)->naddeddisjunctives = 0;
    1821#endif
    1822
    1823 return SCIP_OKAY;
    1824}
    1825
    1826/** frees constraint handler data for logic or constraint handler */
    1827static
    1829 SCIP* scip, /**< SCIP data structure */
    1830 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
    1831 )
    1832{
    1833 assert(conshdlrdata != NULL);
    1834 assert(*conshdlrdata != NULL);
    1835
    1836 SCIPfreeBlockMemory(scip, conshdlrdata);
    1837}
    1838
    1839/**@} */
    1840
    1841
    1842/**@name Constraint data methods
    1843 *
    1844 * @{
    1845 */
    1846
    1847/** catches bound change events for all variables in transformed cumulative constraint */
    1848static
    1850 SCIP* scip, /**< SCIP data structure */
    1851 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
    1852 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    1853 )
    1854{
    1855 int v;
    1856
    1857 assert(scip != NULL);
    1858 assert(consdata != NULL);
    1859 assert(eventhdlr != NULL);
    1860
    1861 /* catch event for every single variable */
    1862 for( v = 0; v < consdata->nvars; ++v )
    1863 {
    1864 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
    1865 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
    1866 }
    1867
    1868 return SCIP_OKAY;
    1869}
    1870
    1871/** drops events for variable at given position */
    1872static
    1874 SCIP* scip, /**< SCIP data structure */
    1875 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
    1876 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
    1877 int pos /**< array position of variable to catch bound change events for */
    1878 )
    1879{
    1880 assert(scip != NULL);
    1881 assert(consdata != NULL);
    1882 assert(eventhdlr != NULL);
    1883 assert(0 <= pos && pos < consdata->nvars);
    1884 assert(consdata->vars[pos] != NULL);
    1885
    1886 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
    1887 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
    1888
    1889 return SCIP_OKAY;
    1890}
    1891
    1892/** drops bound change events for all variables in transformed linear constraint */
    1893static
    1895 SCIP* scip, /**< SCIP data structure */
    1896 SCIP_CONSDATA* consdata, /**< linear constraint data */
    1897 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    1898 )
    1899{
    1900 int v;
    1901
    1902 assert(scip != NULL);
    1903 assert(consdata != NULL);
    1904
    1905 /* drop event of every single variable */
    1906 for( v = 0; v < consdata->nvars; ++v )
    1907 {
    1908 SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
    1909 }
    1910
    1911 return SCIP_OKAY;
    1912}
    1913
    1914/** initialize variable lock data structure */
    1915static
    1917 SCIP_CONSDATA* consdata, /**< constraint data */
    1918 SCIP_Bool locked /**< should the variable be locked? */
    1919 )
    1920{
    1921 int nvars;
    1922 int v;
    1923
    1924 nvars = consdata->nvars;
    1925
    1926 /* initialize locking arrays */
    1927 for( v = 0; v < nvars; ++v )
    1928 {
    1929 consdata->downlocks[v] = locked;
    1930 consdata->uplocks[v] = locked;
    1931 }
    1932}
    1933
    1934/** creates constraint data of cumulative constraint */
    1935static
    1937 SCIP* scip, /**< SCIP data structure */
    1938 SCIP_CONSDATA** consdata, /**< pointer to consdata */
    1939 SCIP_VAR** vars, /**< array of integer variables */
    1940 SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
    1941 int* durations, /**< array containing corresponding durations */
    1942 int* demands, /**< array containing corresponding demands */
    1943 int nvars, /**< number of variables */
    1944 int capacity, /**< available cumulative capacity */
    1945 int hmin, /**< left bound of time axis to be considered (including hmin) */
    1946 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    1947 SCIP_Bool check /**< is the corresponding constraint a check constraint */
    1948 )
    1949{
    1950 int v;
    1951
    1952 assert(scip != NULL);
    1953 assert(consdata != NULL);
    1954 assert(vars != NULL || nvars > 0);
    1955 assert(demands != NULL);
    1956 assert(durations != NULL);
    1957 assert(capacity >= 0);
    1958 assert(hmin >= 0);
    1959 assert(hmin < hmax);
    1960
    1961 /* create constraint data */
    1962 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
    1963
    1964 (*consdata)->hmin = hmin;
    1965 (*consdata)->hmax = hmax;
    1966
    1967 (*consdata)->capacity = capacity;
    1968 (*consdata)->demandrows = NULL;
    1969 (*consdata)->demandrowssize = 0;
    1970 (*consdata)->ndemandrows = 0;
    1971 (*consdata)->scoverrows = NULL;
    1972 (*consdata)->nscoverrows = 0;
    1973 (*consdata)->scoverrowssize = 0;
    1974 (*consdata)->bcoverrows = NULL;
    1975 (*consdata)->nbcoverrows = 0;
    1976 (*consdata)->bcoverrowssize = 0;
    1977 (*consdata)->nvars = nvars;
    1978 (*consdata)->varssize = nvars;
    1979 (*consdata)->signature = 0;
    1980 (*consdata)->validsignature = FALSE;
    1981 (*consdata)->normalized = FALSE;
    1982 (*consdata)->covercuts = FALSE;
    1983 (*consdata)->propagated = FALSE;
    1984 (*consdata)->varbounds = FALSE;
    1985 (*consdata)->triedsolving = FALSE;
    1986
    1987 if( nvars > 0 )
    1988 {
    1989 assert(vars != NULL); /* for flexelint */
    1990
    1991 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
    1992 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
    1993 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
    1994 (*consdata)->linkingconss = NULL;
    1995
    1996 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
    1997 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
    1998
    1999 /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
    2000 initializeLocks(*consdata, check);
    2001
    2002 if( linkingconss != NULL )
    2003 {
    2004 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
    2005 }
    2006
    2007 /* transform variables, if they are not yet transformed */
    2008 if( SCIPisTransformed(scip) )
    2009 {
    2010 SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
    2011
    2012 /* get transformed variables and do NOT captures these */
    2013 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
    2014
    2015 /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
    2016 * been multi-aggregated
    2017 */
    2018 for( v = 0; v < nvars; ++v )
    2019 {
    2020 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
    2021 }
    2022
    2023 if( linkingconss != NULL )
    2024 {
    2025 /* get transformed constraints and captures these */
    2026 SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
    2027
    2028 for( v = 0; v < nvars; ++v )
    2029 assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
    2030 }
    2031 }
    2032
    2033#ifndef NDEBUG
    2034 /* only binary and integer variables can be used in cumulative constraints
    2035 * for fractional variable values, the constraint cannot be checked
    2036 */
    2037 for( v = 0; v < (*consdata)->nvars; ++v )
    2038 assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
    2039#endif
    2040 }
    2041 else
    2042 {
    2043 (*consdata)->vars = NULL;
    2044 (*consdata)->downlocks = NULL;
    2045 (*consdata)->uplocks = NULL;
    2046 (*consdata)->demands = NULL;
    2047 (*consdata)->durations = NULL;
    2048 (*consdata)->linkingconss = NULL;
    2049 }
    2050
    2051 /* initialize values for running propagation algorithms efficiently */
    2052 (*consdata)->resstrength1 = -1.0;
    2053 (*consdata)->resstrength2 = -1.0;
    2054 (*consdata)->cumfactor1 = -1.0;
    2055 (*consdata)->disjfactor1 = -1.0;
    2056 (*consdata)->disjfactor2 = -1.0;
    2057 (*consdata)->estimatedstrength = -1.0;
    2058
    2059 SCIPstatistic( (*consdata)->maxpeak = -1 );
    2060
    2061 return SCIP_OKAY;
    2062}
    2063
    2064/** releases LP rows of constraint data and frees rows array */
    2065static
    2067 SCIP* scip, /**< SCIP data structure */
    2068 SCIP_CONSDATA** consdata /**< constraint data */
    2069 )
    2070{
    2071 int r;
    2072
    2073 assert(consdata != NULL);
    2074 assert(*consdata != NULL);
    2075
    2076 for( r = 0; r < (*consdata)->ndemandrows; ++r )
    2077 {
    2078 assert((*consdata)->demandrows[r] != NULL);
    2079 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
    2080 }
    2081
    2082 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
    2083
    2084 (*consdata)->ndemandrows = 0;
    2085 (*consdata)->demandrowssize = 0;
    2086
    2087 /* free rows of cover cuts */
    2088 for( r = 0; r < (*consdata)->nscoverrows; ++r )
    2089 {
    2090 assert((*consdata)->scoverrows[r] != NULL);
    2091 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
    2092 }
    2093
    2094 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
    2095
    2096 (*consdata)->nscoverrows = 0;
    2097 (*consdata)->scoverrowssize = 0;
    2098
    2099 for( r = 0; r < (*consdata)->nbcoverrows; ++r )
    2100 {
    2101 assert((*consdata)->bcoverrows[r] != NULL);
    2102 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
    2103 }
    2104
    2105 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
    2106
    2107 (*consdata)->nbcoverrows = 0;
    2108 (*consdata)->bcoverrowssize = 0;
    2109
    2110 (*consdata)->covercuts = FALSE;
    2111
    2112 return SCIP_OKAY;
    2113}
    2114
    2115/** frees a cumulative constraint data */
    2116static
    2118 SCIP* scip, /**< SCIP data structure */
    2119 SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
    2120 )
    2121{
    2122 int varssize;
    2123 int nvars;
    2124
    2125 assert(consdata != NULL);
    2126 assert(*consdata != NULL);
    2127
    2128 nvars = (*consdata)->nvars;
    2129 varssize = (*consdata)->varssize;
    2130
    2131 if( varssize > 0 )
    2132 {
    2133 int v;
    2134
    2135 /* release and free the rows */
    2136 SCIP_CALL( consdataFreeRows(scip, consdata) );
    2137
    2138 /* release the linking constraints if they were generated */
    2139 if( (*consdata)->linkingconss != NULL )
    2140 {
    2141 for( v = nvars-1; v >= 0; --v )
    2142 {
    2143 assert((*consdata)->linkingconss[v] != NULL );
    2144 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
    2145 }
    2146
    2147 SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
    2148 }
    2149
    2150 /* free arrays */
    2151 SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
    2152 SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
    2153 SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
    2154 SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
    2155 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
    2156 }
    2157
    2158 /* free memory */
    2159 SCIPfreeBlockMemory(scip, consdata);
    2160
    2161 return SCIP_OKAY;
    2162}
    2163
    2164/** prints cumulative constraint to file stream */
    2165static
    2167 SCIP* scip, /**< SCIP data structure */
    2168 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
    2169 FILE* file /**< output file (or NULL for standard output) */
    2170 )
    2171{
    2172 int v;
    2173
    2174 assert(consdata != NULL);
    2175
    2176 /* print coefficients */
    2177 SCIPinfoMessage( scip, file, "cumulative(");
    2178
    2179 for( v = 0; v < consdata->nvars; ++v )
    2180 {
    2181 assert(consdata->vars[v] != NULL);
    2182 if( v > 0 )
    2183 SCIPinfoMessage(scip, file, ", ");
    2184 SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
    2185 SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
    2186 consdata->durations[v], consdata->demands[v]);
    2187 }
    2188 SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
    2189}
    2190
    2191/** deletes coefficient at given position from constraint data */
    2192static
    2194 SCIP* scip, /**< SCIP data structure */
    2195 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
    2196 SCIP_CONS* cons, /**< knapsack constraint */
    2197 int pos /**< position of coefficient to delete */
    2198 )
    2199{
    2200 SCIP_CONSHDLR* conshdlr;
    2201 SCIP_CONSHDLRDATA* conshdlrdata;
    2202
    2203 assert(scip != NULL);
    2204 assert(consdata != NULL);
    2205 assert(cons != NULL);
    2206 assert(SCIPconsIsTransformed(cons));
    2207 assert(!SCIPinProbing(scip));
    2208
    2209 SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
    2210 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
    2211
    2212 /* remove the rounding locks for the deleted variable */
    2213 SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
    2214
    2215 consdata->downlocks[pos] = FALSE;
    2216 consdata->uplocks[pos] = FALSE;
    2217
    2218 if( consdata->linkingconss != NULL )
    2219 {
    2220 SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
    2221 }
    2222
    2223 /* get event handler */
    2224 conshdlr = SCIPconsGetHdlr(cons);
    2225 assert(conshdlr != NULL);
    2226 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2227 assert(conshdlrdata != NULL);
    2228 assert(conshdlrdata->eventhdlr != NULL);
    2229
    2230 /* drop events */
    2231 SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
    2232
    2233 SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
    2234 SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
    2235
    2236 /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
    2237 * position
    2238 */
    2239 if( pos != consdata->nvars - 1 )
    2240 {
    2241 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
    2242 consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
    2243 consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
    2244 consdata->demands[pos] = consdata->demands[consdata->nvars-1];
    2245 consdata->durations[pos] = consdata->durations[consdata->nvars-1];
    2246
    2247 if( consdata->linkingconss != NULL )
    2248 {
    2249 consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
    2250 }
    2251 }
    2252
    2253 consdata->nvars--;
    2254 consdata->validsignature = FALSE;
    2255 consdata->normalized = FALSE;
    2256
    2257 return SCIP_OKAY;
    2258}
    2259
    2260/** collect linking constraints for each integer variable */
    2261static
    2263 SCIP* scip, /**< SCIP data structure */
    2264 SCIP_CONSDATA* consdata /**< pointer to consdata */
    2265 )
    2266{
    2267 int nvars;
    2268 int v;
    2269
    2270 assert(scip != NULL);
    2271 assert(consdata != NULL);
    2272
    2273 nvars = consdata->nvars;
    2274 assert(nvars > 0);
    2275 assert(consdata->linkingconss == NULL);
    2276
    2277 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
    2278
    2279 for( v = 0; v < nvars; ++v )
    2280 {
    2281 SCIP_CONS* cons;
    2282 SCIP_VAR* var;
    2283
    2284 var = consdata->vars[v];
    2285 assert(var != NULL);
    2286
    2287 SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
    2288
    2289 /* create linking constraint if it does not exist yet */
    2290 if( !SCIPexistsConsLinking(scip, var) )
    2291 {
    2292 char name[SCIP_MAXSTRLEN];
    2293
    2294 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
    2295
    2296 /* creates and captures an linking constraint */
    2297 SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
    2298 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
    2299 SCIP_CALL( SCIPaddCons(scip, cons) );
    2300 consdata->linkingconss[v] = cons;
    2301 }
    2302 else
    2303 {
    2304 consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
    2305 SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
    2306 }
    2307
    2308 assert(SCIPexistsConsLinking(scip, var));
    2309 assert(consdata->linkingconss[v] != NULL);
    2310 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
    2311 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
    2312 }
    2313
    2314 return SCIP_OKAY;
    2315}
    2316
    2317/**@} */
    2318
    2319
    2320/**@name Check methods
    2321 *
    2322 * @{
    2323 */
    2324
    2325/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
    2326 * given solution is satisfied
    2327 */
    2328static
    2330 SCIP* scip, /**< SCIP data structure */
    2331 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    2332 int nvars, /**< number of variables (jobs) */
    2333 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    2334 int* durations, /**< array containing corresponding durations */
    2335 int* demands, /**< array containing corresponding demands */
    2336 int capacity, /**< available cumulative capacity */
    2337 int hmin, /**< left bound of time axis to be considered (including hmin) */
    2338 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    2339 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
    2340 SCIP_CONS* cons, /**< constraint which is checked */
    2341 SCIP_Bool printreason /**< should the reason for the violation be printed? */
    2342 )
    2343{
    2344 int* startsolvalues; /* stores when each job is starting */
    2345 int* endsolvalues; /* stores when each job ends */
    2346 int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
    2347 int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
    2348
    2349 int freecapacity;
    2350 int curtime; /* point in time which we are just checking */
    2351 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    2352 int j;
    2353
    2354 SCIP_Real absviol;
    2355 SCIP_Real relviol;
    2356
    2357 assert(scip != NULL);
    2358 assert(violated != NULL);
    2359
    2360 (*violated) = FALSE;
    2361
    2362 if( nvars == 0 )
    2363 return SCIP_OKAY;
    2364
    2365 assert(vars != NULL);
    2366 assert(demands != NULL);
    2367 assert(durations != NULL);
    2368
    2369 /* compute time points where we have to check whether capacity constraint is infeasible or not */
    2370 SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
    2371 SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
    2372 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    2373 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    2374
    2375 /* assign variables, start and endpoints to arrays */
    2376 for ( j = 0; j < nvars; ++j )
    2377 {
    2378 int solvalue;
    2379
    2380 /* the constraint of the cumulative constraint handler should be called after the integrality check */
    2381 assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
    2382
    2383 solvalue = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
    2384
    2385 /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
    2386 * jobs which start before hmin to hmin
    2387 */
    2388 startsolvalues[j] = MAX(solvalue, hmin);
    2389 startindices[j] = j;
    2390
    2391 endsolvalues[j] = MAX(solvalue + durations[j], hmin);
    2392 endindices[j] = j;
    2393 }
    2394
    2395 /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
    2396 * corresponding indices in the same way)
    2397 */
    2398 SCIPsortIntInt(startsolvalues, startindices, nvars);
    2399 SCIPsortIntInt(endsolvalues, endindices, nvars);
    2400
    2401 endindex = 0;
    2402 freecapacity = capacity;
    2403 absviol = 0.0;
    2404 relviol = 0.0;
    2405
    2406 /* check each start point of a job whether the capacity is kept or not */
    2407 for( j = 0; j < nvars; ++j )
    2408 {
    2409 /* only check intervals [hmin,hmax) */
    2410 curtime = startsolvalues[j];
    2411
    2412 if( curtime >= hmax )
    2413 break;
    2414
    2415 /* subtract all capacity needed up to this point */
    2416 freecapacity -= demands[startindices[j]];
    2417 while( j+1 < nvars && startsolvalues[j+1] == curtime )
    2418 {
    2419 j++;
    2420 freecapacity -= demands[startindices[j]];
    2421 }
    2422
    2423 /* free all capacity usages of jobs that are no longer running */
    2424 while( endindex < nvars && curtime >= endsolvalues[endindex] )
    2425 {
    2426 freecapacity += demands[endindices[endindex]];
    2427 ++endindex;
    2428 }
    2429 assert(freecapacity <= capacity);
    2430
    2431 /* update absolute and relative violation */
    2432 if( absviol < (SCIP_Real) (-freecapacity) )
    2433 {
    2434 absviol = -freecapacity;
    2435 relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
    2436 }
    2437
    2438 /* check freecapacity to be smaller than zero */
    2439 if( freecapacity < 0 && curtime >= hmin )
    2440 {
    2441 SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
    2442 (*violated) = TRUE;
    2443
    2444 if( printreason )
    2445 {
    2446 int i;
    2447
    2448 /* first state the violated constraints */
    2449 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    2450
    2451 /* second state the reason */
    2453 ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
    2454 curtime, capacity, capacity - freecapacity);
    2455
    2456 for( i = 0; i <= j; ++i )
    2457 {
    2458 if( startsolvalues[i] + durations[startindices[i]] > curtime )
    2459 {
    2460 SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
    2461 SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
    2462 demands[startindices[i]]);
    2463 }
    2464 }
    2465 }
    2466 break;
    2467 }
    2468 } /*lint --e{850}*/
    2469
    2470 /* update constraint violation in solution */
    2471 if( sol != NULL )
    2472 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
    2473
    2474 /* free all buffer arrays */
    2475 SCIPfreeBufferArray(scip, &endindices);
    2476 SCIPfreeBufferArray(scip, &startindices);
    2477 SCIPfreeBufferArray(scip, &endsolvalues);
    2478 SCIPfreeBufferArray(scip, &startsolvalues);
    2479
    2480 return SCIP_OKAY;
    2481}
    2482
    2483/** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
    2484 * least zero or not. If not (*violated) is set to TRUE
    2485 */
    2486static
    2488 SCIP* scip, /**< SCIP data structure */
    2489 SCIP_CONS* cons, /**< constraint to be checked */
    2490 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    2491 SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
    2492 SCIP_Bool printreason /**< should the reason for the violation be printed? */
    2493 )
    2494{
    2495 SCIP_CONSDATA* consdata;
    2496
    2497 assert(scip != NULL);
    2498 assert(cons != NULL);
    2499 assert(violated != NULL);
    2500
    2501 SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
    2502
    2503 consdata = SCIPconsGetData(cons);
    2504 assert(consdata != NULL);
    2505
    2506 /* check the cumulative condition */
    2507 SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
    2508 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
    2509 violated, cons, printreason) );
    2510
    2511 return SCIP_OKAY;
    2512}
    2513
    2514/**@} */
    2515
    2516/**@name Conflict analysis
    2517 *
    2518 * @{
    2519 */
    2520
    2521/** resolves the propagation of the core time algorithm */
    2522static
    2524 SCIP* scip, /**< SCIP data structure */
    2525 int nvars, /**< number of start time variables (activities) */
    2526 SCIP_VAR** vars, /**< array of start time variables */
    2527 int* durations, /**< array of durations */
    2528 int* demands, /**< array of demands */
    2529 int capacity, /**< cumulative capacity */
    2530 int hmin, /**< left bound of time axis to be considered (including hmin) */
    2531 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    2532 SCIP_VAR* infervar, /**< inference variable */
    2533 int inferdemand, /**< demand of the inference variable */
    2534 int inferpeak, /**< time point which causes the propagation */
    2535 int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
    2536 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
    2537 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    2538 int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
    2539 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    2540 )
    2541{
    2542 SCIP_VAR* var;
    2543 SCIP_Bool* reported;
    2544 int duration;
    2545 int maxlst;
    2546 int minect;
    2547 int ect;
    2548 int lst;
    2549 int j;
    2550
    2552
    2553 SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
    2554 SCIPvarGetName(infervar), inferdemand, inferpeak);
    2555 assert(nvars > 0);
    2556
    2557 /* adjusted capacity */
    2558 capacity -= inferdemand;
    2559 maxlst = INT_MIN;
    2560 minect = INT_MAX;
    2561
    2562 SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
    2563 BMSclearMemoryArray(reported, nvars);
    2564
    2565 /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
    2566 * inference peak and those where the current conflict bounds provide a core at the inference peak
    2567 */
    2568 for( j = 0; j < nvars && capacity >= 0; ++j )
    2569 {
    2570 var = vars[j];
    2571 assert(var != NULL);
    2572
    2573 /* skip inference variable */
    2574 if( var == infervar )
    2575 continue;
    2576
    2577 duration = durations[j];
    2578 assert(duration > 0);
    2579
    2580 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
    2581 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
    2582 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
    2583 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
    2584 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
    2585
    2586 SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
    2588 SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
    2589
    2590 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
    2592
    2593 /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
    2594 * that job without adding it the explanation
    2595 */
    2596 if( inferpeak < ect && lst <= inferpeak )
    2597 {
    2598 capacity -= demands[j];
    2599 reported[j] = TRUE;
    2600
    2601 maxlst = MAX(maxlst, lst);
    2602 minect = MIN(minect, ect);
    2603 assert(maxlst < minect);
    2604
    2605 if( explanation != NULL )
    2606 explanation[j] = TRUE;
    2607
    2608 continue;
    2609 }
    2610
    2611 /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
    2612 * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
    2613 * not part of the conflict yet we get the global bounds back.
    2614 */
    2615 ect = boundedConvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
    2617
    2618 /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
    2619 * of that job without and collect the job as part of the explanation
    2620 *
    2621 * @note we do not need to reported that job to SCIP since the required bounds are already reported
    2622 */
    2623 if( inferpeak < ect && lst <= inferpeak )
    2624 {
    2625 capacity -= demands[j];
    2626 reported[j] = TRUE;
    2627
    2628 maxlst = MAX(maxlst, lst);
    2629 minect = MIN(minect, ect);
    2630 assert(maxlst < minect);
    2631
    2632 if( explanation != NULL )
    2633 explanation[j] = TRUE;
    2634 }
    2635 }
    2636
    2637 if( capacity >= 0 )
    2638 {
    2639 int* cands;
    2640 int* canddemands;
    2641 int ncands;
    2642 int c;
    2643
    2644 SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
    2645 SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
    2646 ncands = 0;
    2647
    2648 /* collect all cores of the variables which lay in the considered time window except the inference variable */
    2649 for( j = 0; j < nvars; ++j )
    2650 {
    2651 var = vars[j];
    2652 assert(var != NULL);
    2653
    2654 /* skip inference variable */
    2655 if( var == infervar || reported[j] )
    2656 continue;
    2657
    2658 duration = durations[j];
    2659 assert(duration > 0);
    2660
    2661 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
    2662 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
    2663 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
    2664 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
    2665 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
    2666
    2667 /* collect local core information */
    2668 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
    2670
    2671 SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
    2672 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
    2673 SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
    2674
    2675 /* check if the inference peak is part of the core */
    2676 if( inferpeak < ect && lst <= inferpeak )
    2677 {
    2678 cands[ncands] = j;
    2679 canddemands[ncands] = demands[j];
    2680 ncands++;
    2681
    2682 capacity -= demands[j];
    2683 }
    2684 }
    2685
    2686 /* sort candidates indices w.r.t. their demands */
    2687 SCIPsortDownIntInt(canddemands, cands, ncands);
    2688
    2689 assert(capacity < 0);
    2690 assert(ncands > 0);
    2691
    2692 /* greedily remove candidates form the list such that the needed capacity is still exceeded */
    2693 while( capacity + canddemands[ncands-1] < 0 )
    2694 {
    2695 ncands--;
    2696 capacity += canddemands[ncands];
    2697 assert(ncands > 0);
    2698 }
    2699
    2700 /* compute the size (number of time steps) of the job cores */
    2701 for( c = 0; c < ncands; ++c )
    2702 {
    2703 var = vars[cands[c]];
    2704 assert(var != NULL);
    2705
    2706 duration = durations[cands[c]];
    2707
    2708 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
    2710
    2711 maxlst = MAX(maxlst, lst);
    2712 minect = MIN(minect, ect);
    2713 assert(maxlst < minect);
    2714 }
    2715
    2716 SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
    2717 assert(inferpeak >= maxlst);
    2718 assert(inferpeak < minect);
    2719
    2720 /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
    2721 if( relaxedpeak < inferpeak )
    2722 {
    2723 inferpeak = MAX(maxlst, relaxedpeak);
    2724 }
    2725 else if( relaxedpeak > inferpeak )
    2726 {
    2727 inferpeak = MIN(minect-1, relaxedpeak);
    2728 }
    2729 assert(inferpeak >= hmin);
    2730 assert(inferpeak < hmax);
    2731 assert(inferpeak >= maxlst);
    2732 assert(inferpeak < minect);
    2733
    2734 /* post all necessary bound changes */
    2735 for( c = 0; c < ncands; ++c )
    2736 {
    2737 var = vars[cands[c]];
    2738 assert(var != NULL);
    2739
    2740 if( usebdwidening )
    2741 {
    2742 duration = durations[cands[c]];
    2743
    2744 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
    2745 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
    2746 }
    2747 else
    2748 {
    2749 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
    2750 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
    2751 }
    2752
    2753 if( explanation != NULL )
    2754 explanation[cands[c]] = TRUE;
    2755 }
    2756
    2757 SCIPfreeBufferArray(scip, &canddemands);
    2758 SCIPfreeBufferArray(scip, &cands);
    2759 }
    2760
    2761 SCIPfreeBufferArray(scip, &reported);
    2762
    2763 if( provedpeak != NULL )
    2764 *provedpeak = inferpeak;
    2765
    2766 return SCIP_OKAY;
    2767}
    2768
    2769/** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
    2770static
    2772 int begin, /**< begin of the times interval */
    2773 int end, /**< end of time interval */
    2774 int est, /**< earliest start time */
    2775 int lst, /**< latest start time */
    2776 int duration /**< duration of the job */
    2777 )
    2778{
    2779 int left;
    2780 int right;
    2781 int ect;
    2782 int lct;
    2783
    2784 ect = est + duration;
    2785 lct = lst + duration;
    2786
    2787 /* check if job runs completely within [begin,end) */
    2788 if( lct <= end && est >= begin )
    2789 return duration;
    2790
    2791 assert(lst <= end && ect >= begin);
    2792
    2793 left = ect - begin;
    2794 assert(left > 0);
    2795
    2796 right = end - lst;
    2797 assert(right > 0);
    2798
    2799 return MIN3(left, right, end - begin);
    2800}
    2801
    2802/** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
    2803 * reason
    2804 *
    2805 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
    2806 */
    2807static
    2809 SCIP* scip, /**< SCIP data structure */
    2810 int nvars, /**< number of start time variables (activities) */
    2811 SCIP_VAR** vars, /**< array of start time variables */
    2812 int* durations, /**< array of durations */
    2813 int* demands, /**< array of demands */
    2814 int capacity, /**< capacity of the cumulative condition */
    2815 int begin, /**< begin of the time window */
    2816 int end, /**< end of the time window */
    2817 SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
    2818 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
    2819 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
    2820 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
    2821 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    2822 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    2823 )
    2824{
    2825 int* locenergies;
    2826 int* overlaps;
    2827 int* idxs;
    2828
    2829 SCIP_Longint requiredenergy;
    2830 int v;
    2831
    2832 SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
    2833 SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
    2834 SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
    2835
    2836 /* energy which needs be explained */
    2837 requiredenergy = ((SCIP_Longint) end - begin) * capacity;
    2838
    2839 SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
    2840
    2841 /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
    2842 * takes
    2843 */
    2844 for( v = 0; v < nvars; ++v )
    2845 {
    2846 SCIP_VAR* var;
    2847 int glbenergy;
    2848 int duration;
    2849 int demand;
    2850 int est;
    2851 int lst;
    2852
    2853 var = vars[v];
    2854 assert(var != NULL);
    2855
    2856 locenergies[v] = 0;
    2857 overlaps[v] = 0;
    2858 idxs[v] = v;
    2859
    2860 demand = demands[v];
    2861 assert(demand > 0);
    2862
    2863 duration = durations[v];
    2864 assert(duration > 0);
    2865
    2866 /* check if the variable equals the inference variable (the one which was propagated) */
    2867 if( infervar == var )
    2868 {
    2869 int overlap;
    2870 int right;
    2871 int left;
    2872
    2873 assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
    2874
    2875 SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
    2876 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
    2877 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
    2878
    2879 /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
    2880 * which is necessary from the inference variable
    2881 */
    2882 if( boundtype == SCIP_BOUNDTYPE_UPPER )
    2883 {
    2884 int lct;
    2885
    2886 /* get the latest start time of the infer start time variable before the propagation took place */
    2888
    2889 /* the latest start time of the inference start time variable before the propagation needs to be smaller as
    2890 * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
    2891 * scheduled w.r.t. its latest start time
    2892 */
    2893 assert(lst < end);
    2894
    2895 /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
    2896 * interval (before the propagation)
    2897 */
    2898 right = MIN3(end - lst, end - begin, duration);
    2899
    2900 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
    2901 assert(right > 0);
    2902
    2903 lct = boundedConvertRealToInt(scip, relaxedbd) + duration;
    2904 assert(begin <= lct);
    2905 assert(bdchgidx == NULL ||
    2906 boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
    2907
    2908 /* compute the overlap of the job after the propagation but considering the relaxed bound */
    2909 left = MIN(lct - begin + 1, end - begin);
    2910 assert(left > 0);
    2911
    2912 /* compute the minimum overlap; */
    2913 overlap = MIN(left, right);
    2914 assert(overlap > 0);
    2915 assert(overlap <= end - begin);
    2916 assert(overlap <= duration);
    2917
    2918 if( usebdwidening )
    2919 {
    2920 assert(boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
    2921 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
    2922 }
    2923 else
    2924 {
    2925 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
    2926 }
    2927 }
    2928 else
    2929 {
    2930 int ect;
    2931
    2932 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
    2933
    2934 /* get the earliest completion time of the infer start time variable before the propagation took place */
    2935 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
    2936
    2937 /* the earliest start time of the inference start time variable before the propagation needs to be larger as
    2938 * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
    2939 * the job is scheduled w.r.t. its earliest start time
    2940 */
    2941 assert(ect > begin);
    2942
    2943 /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
    2944 * interval (before the propagation)
    2945 */
    2946 left = MIN3(ect - begin, end - begin, duration);
    2947
    2948 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
    2949 assert(left > 0);
    2950
    2951 est = boundedConvertRealToInt(scip, relaxedbd);
    2952 assert(end >= est);
    2953 assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
    2954
    2955 /* compute the overlap of the job after the propagation but considering the relaxed bound */
    2956 right = MIN(end - est + 1, end - begin);
    2957 assert(right > 0);
    2958
    2959 /* compute the minimum overlap */
    2960 overlap = MIN(left, right);
    2961 assert(overlap > 0);
    2962 assert(overlap <= end - begin);
    2963 assert(overlap <= duration);
    2964
    2965 if( usebdwidening )
    2966 {
    2967 assert(boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
    2968 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
    2969 }
    2970 else
    2971 {
    2972 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
    2973 }
    2974 }
    2975
    2976 /* subtract the amount of energy which is available due to the overlap of the inference start time */
    2977 requiredenergy -= (SCIP_Longint) overlap * demand;
    2978
    2979 if( explanation != NULL )
    2980 explanation[v] = TRUE;
    2981
    2982 continue;
    2983 }
    2984
    2985 /* global time points */
    2988
    2989 glbenergy = 0;
    2990
    2991 /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
    2992 * time window
    2993 */
    2994 if( est + duration > begin && lst < end )
    2995 {
    2996 /* evaluated global contribution */
    2997 glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
    2998
    2999 /* remove the globally available energy form the required energy */
    3000 requiredenergy -= glbenergy;
    3001
    3002 if( explanation != NULL )
    3003 explanation[v] = TRUE;
    3004 }
    3005
    3006 /* local time points */
    3009
    3010 /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
    3011 * time window
    3012 */
    3013 if( est + duration > begin && lst < end )
    3014 {
    3015 overlaps[v] = computeOverlap(begin, end, est, lst, duration);
    3016
    3017 /* evaluated additionally local energy contribution */
    3018 locenergies[v] = overlaps[v] * demand - glbenergy;
    3019 assert(locenergies[v] >= 0);
    3020 }
    3021 }
    3022
    3023 /* sort the variable contributions w.r.t. additional local energy contributions */
    3024 SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
    3025
    3026 /* add local energy contributions until an overload is implied */
    3027 for( v = 0; v < nvars && requiredenergy >= 0; ++v )
    3028 {
    3029 SCIP_VAR* var;
    3030 int duration;
    3031 int overlap;
    3032 int relaxlb;
    3033 int relaxub;
    3034 int idx;
    3035
    3036 idx = idxs[v];
    3037 assert(idx >= 0 && idx < nvars);
    3038
    3039 var = vars[idx];
    3040 assert(var != NULL);
    3041 assert(var != infervar);
    3042
    3043 duration = durations[idx];
    3044 assert(duration > 0);
    3045
    3046 overlap = overlaps[v];
    3047 assert(overlap > 0);
    3048
    3049 requiredenergy -= locenergies[v];
    3050
    3051 if( requiredenergy < -1 )
    3052 {
    3053 int demand;
    3054
    3055 demand = demands[idx];
    3056 assert(demand > 0);
    3057
    3058 overlap += (int)((requiredenergy + 1) / demand);
    3059
    3060#ifndef NDEBUG
    3061 requiredenergy += locenergies[v];
    3062 requiredenergy -= (SCIP_Longint) overlap * demand;
    3063 assert(requiredenergy < 0);
    3064#endif
    3065 }
    3066 assert(overlap > 0);
    3067
    3068 relaxlb = begin - duration + overlap;
    3069 relaxub = end - overlap;
    3070
    3071 SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
    3072 SCIPvarGetName(var),
    3076 relaxlb, relaxub, demands[idx], duration);
    3077
    3078 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
    3079 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
    3080
    3081 if( explanation != NULL )
    3082 explanation[idx] = TRUE;
    3083 }
    3084
    3085 assert(requiredenergy < 0);
    3086
    3087 SCIPfreeBufferArray(scip, &idxs);
    3088 SCIPfreeBufferArray(scip, &overlaps);
    3089 SCIPfreeBufferArray(scip, &locenergies);
    3090
    3091 return SCIP_OKAY;
    3092}
    3093
    3094/** resolve propagation w.r.t. the cumulative condition */
    3095static
    3097 SCIP* scip, /**< SCIP data structure */
    3098 int nvars, /**< number of start time variables (activities) */
    3099 SCIP_VAR** vars, /**< array of start time variables */
    3100 int* durations, /**< array of durations */
    3101 int* demands, /**< array of demands */
    3102 int capacity, /**< cumulative capacity */
    3103 int hmin, /**< left bound of time axis to be considered (including hmin) */
    3104 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    3105 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
    3106 INFERINFO inferinfo, /**< the user information */
    3107 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
    3108 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
    3109 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
    3110 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    3111 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    3112 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
    3113 )
    3114{
    3115 switch( inferInfoGetProprule(inferinfo) )
    3116 {
    3118 {
    3119 int inferdemand;
    3120 int inferduration;
    3121 int inferpos;
    3122 int inferpeak;
    3123 int relaxedpeak;
    3124 int provedpeak;
    3125
    3126 /* get the position of the inferred variable in the vars array */
    3127 inferpos = inferInfoGetData1(inferinfo);
    3128 if( inferpos >= nvars || vars[inferpos] != infervar )
    3129 {
    3130 /* find inference variable in constraint */
    3131 for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
    3132 {}
    3133 }
    3134 assert(inferpos < nvars);
    3135 assert(vars[inferpos] == infervar);
    3136
    3137 inferdemand = demands[inferpos];
    3138 inferduration = durations[inferpos];
    3139
    3140 if( boundtype == SCIP_BOUNDTYPE_UPPER )
    3141 {
    3142 /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
    3143 * the inference variable
    3144 */
    3145 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
    3146
    3147 SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
    3148 SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
    3149 SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
    3150
    3151 /* get the inference peak that the time point which lead to the that propagtion */
    3152 inferpeak = inferInfoGetData2(inferinfo);
    3153 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
    3154 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
    3155 */
    3156 assert(
    3157 boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
    3158 relaxedpeak = boundedConvertRealToInt(scip, relaxedbd) + inferduration;
    3159
    3160 /* make sure that the relaxed peak is part of the effective horizon */
    3161 relaxedpeak = MIN(relaxedpeak, hmax-1);
    3162
    3163 /* make sure that relaxed peak is not larger than the infer peak
    3164 *
    3165 * This can happen in case the variable is not an active variable!
    3166 */
    3167 relaxedpeak = MAX(relaxedpeak, inferpeak);
    3168 assert(relaxedpeak >= inferpeak);
    3169 assert(relaxedpeak >= hmin);
    3170 }
    3171 else
    3172 {
    3173 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
    3174
    3175 SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
    3176 SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
    3177 SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
    3178
    3179 /* get the time interval where the job could not be scheduled */
    3180 inferpeak = inferInfoGetData2(inferinfo);
    3181 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
    3182 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
    3183 */
    3184 assert(boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
    3185 relaxedpeak = boundedConvertRealToInt(scip, relaxedbd) - 1;
    3186
    3187 /* make sure that the relaxed peak is part of the effective horizon */
    3188 relaxedpeak = MAX(relaxedpeak, hmin);
    3189
    3190 /* make sure that relaxed peak is not larger than the infer peak
    3191 *
    3192 * This can happen in case the variable is not an active variable!
    3193 */
    3194 relaxedpeak = MIN(relaxedpeak, inferpeak);
    3195 assert(relaxedpeak < hmax);
    3196 }
    3197
    3198 /* resolves the propagation of the core time algorithm */
    3199 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    3200 infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
    3201
    3202 if( boundtype == SCIP_BOUNDTYPE_UPPER )
    3203 {
    3204 if( usebdwidening )
    3205 {
    3206 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
    3207 }
    3208 else
    3209 {
    3210 /* old upper bound of variable itself is part of the explanation */
    3211 SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
    3212 }
    3213 }
    3214 else
    3215 {
    3216 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
    3217
    3218 if( usebdwidening )
    3219 {
    3220 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
    3221 }
    3222 else
    3223 {
    3224 /* old lower bound of variable itself is part of the explanation */
    3225 SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
    3226 }
    3227 }
    3228
    3229 if( explanation != NULL )
    3230 explanation[inferpos] = TRUE;
    3231
    3232 break;
    3233 }
    3235 case PROPRULE_3_TTEF:
    3236 {
    3237 int begin;
    3238 int end;
    3239
    3240 begin = inferInfoGetData1(inferinfo);
    3241 end = inferInfoGetData2(inferinfo);
    3242 assert(begin < end);
    3243
    3244 begin = MAX(begin, hmin);
    3245 end = MIN(end, hmax);
    3246
    3247 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    3248 begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
    3249
    3250 break;
    3251 }
    3252
    3253 case PROPRULE_0_INVALID:
    3254 default:
    3255 SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
    3256 SCIPABORT();
    3257 return SCIP_INVALIDDATA; /*lint !e527*/
    3258 }
    3259
    3260 (*result) = SCIP_SUCCESS;
    3261
    3262 return SCIP_OKAY;
    3263}
    3264
    3265/**@} */
    3266
    3267
    3268/**@name Enforcement methods
    3269 *
    3270 * @{
    3271 */
    3272
    3273/** apply all fixings which are given by the alternative bounds */
    3274static
    3276 SCIP* scip, /**< SCIP data structure */
    3277 SCIP_VAR** vars, /**< array of active variables */
    3278 int nvars, /**< number of active variables */
    3279 int* alternativelbs, /**< alternative lower bounds */
    3280 int* alternativeubs, /**< alternative lower bounds */
    3281 int* downlocks, /**< number of constraints with down lock participating by the computation */
    3282 int* uplocks, /**< number of constraints with up lock participating by the computation */
    3283 SCIP_Bool* branched /**< pointer to store if a branching was applied */
    3284 )
    3285{
    3286 int v;
    3287
    3288 for( v = 0; v < nvars; ++v )
    3289 {
    3290 SCIP_VAR* var;
    3291 SCIP_Real objval;
    3292
    3293 var = vars[v];
    3294 assert(var != NULL);
    3295
    3296 objval = SCIPvarGetObj(var);
    3297
    3298 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
    3299 {
    3300 int ub;
    3301
    3303
    3304 if( alternativelbs[v] <= ub )
    3305 {
    3306 SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
    3307 (*branched) = TRUE;
    3308
    3309 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
    3310 SCIPvarGetLbLocal(var), alternativelbs[v]);
    3311
    3312 return SCIP_OKAY;
    3313 }
    3314 }
    3315
    3316 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
    3317 {
    3318 int lb;
    3319
    3321
    3322 if( alternativeubs[v] >= lb )
    3323 {
    3324 SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
    3325 (*branched) = TRUE;
    3326
    3327 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
    3328 alternativeubs[v], SCIPvarGetUbLocal(var));
    3329
    3330 return SCIP_OKAY;
    3331 }
    3332 }
    3333 }
    3334
    3335 return SCIP_OKAY;
    3336}
    3337
    3338/** remove the capacity requirments for all job which start at the curtime */
    3339static
    3341 SCIP_CONSDATA* consdata, /**< constraint data */
    3342 int curtime, /**< current point in time */
    3343 int* starttimes, /**< array of start times */
    3344 int* startindices, /**< permutation with respect to the start times */
    3345 int* freecapacity, /**< pointer to store the resulting free capacity */
    3346 int* idx, /**< pointer to index in start time array */
    3347 int nvars /**< number of vars in array of starttimes and startindices */
    3348 )
    3349{
    3350#if defined SCIP_DEBUG && !defined NDEBUG
    3351 int oldidx;
    3352
    3353 assert(idx != NULL);
    3354 oldidx = *idx;
    3355#else
    3356 assert(idx != NULL);
    3357#endif
    3358
    3359 assert(starttimes != NULL);
    3360 assert(starttimes != NULL);
    3361 assert(freecapacity != NULL);
    3362 assert(starttimes[*idx] == curtime);
    3363 assert(consdata->demands != NULL);
    3364 assert(freecapacity != idx);
    3365
    3366 /* subtract all capacity needed up to this point */
    3367 (*freecapacity) -= consdata->demands[startindices[*idx]];
    3368
    3369 while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
    3370 {
    3371 ++(*idx);
    3372 (*freecapacity) -= consdata->demands[startindices[(*idx)]];
    3373 assert(freecapacity != idx);
    3374 }
    3375#ifdef SCIP_DEBUG
    3376 assert(oldidx <= *idx);
    3377#endif
    3378}
    3379
    3380/** add the capacity requirments for all job which end at the curtime */
    3381static
    3383 SCIP_CONSDATA* consdata, /**< constraint data */
    3384 int curtime, /**< current point in time */
    3385 int* endtimes, /**< array of end times */
    3386 int* endindices, /**< permutation with rspect to the end times */
    3387 int* freecapacity, /**< pointer to store the resulting free capacity */
    3388 int* idx, /**< pointer to index in end time array */
    3389 int nvars /**< number of vars in array of starttimes and startindices */
    3390 )
    3391{
    3392#if defined SCIP_DEBUG && !defined NDEBUG
    3393 int oldidx;
    3394 oldidx = *idx;
    3395#endif
    3396
    3397 /* free all capacity usages of jobs the are no longer running */
    3398 while( endtimes[*idx] <= curtime && *idx < nvars)
    3399 {
    3400 (*freecapacity) += consdata->demands[endindices[*idx]];
    3401 ++(*idx);
    3402 }
    3403
    3404#ifdef SCIP_DEBUG
    3405 assert(oldidx <= *idx);
    3406#endif
    3407}
    3408
    3409/** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
    3410static
    3412 SCIP* scip, /**< SCIP data structure */
    3413 SCIP_CONSDATA* consdata, /**< constraint handler data */
    3414 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    3415 int* timepoint /**< pointer to store the time point of the peak */
    3416 )
    3417{
    3418 int* starttimes; /* stores when each job is starting */
    3419 int* endtimes; /* stores when each job ends */
    3420 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    3421 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    3422
    3423 int nvars; /* number of activities for this constraint */
    3424 int freecapacity; /* remaining capacity */
    3425 int curtime; /* point in time which we are just checking */
    3426 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    3427
    3428 int hmin;
    3429 int hmax;
    3430
    3431 int j;
    3432
    3433 assert(consdata != NULL);
    3434
    3435 nvars = consdata->nvars;
    3436 assert(nvars > 0);
    3437
    3438 *timepoint = consdata->hmax;
    3439
    3440 assert(consdata->vars != NULL);
    3441
    3442 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    3443 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    3444 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    3445 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    3446
    3447 /* create event point arrays */
    3448 createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
    3449 starttimes, endtimes, startindices, endindices);
    3450
    3451 endindex = 0;
    3452 freecapacity = consdata->capacity;
    3453 hmin = consdata->hmin;
    3454 hmax = consdata->hmax;
    3455
    3456 /* check each startpoint of a job whether the capacity is kept or not */
    3457 for( j = 0; j < nvars; ++j )
    3458 {
    3459 curtime = starttimes[j];
    3460 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
    3461
    3462 if( curtime >= hmax )
    3463 break;
    3464
    3465 /* remove the capacity requirments for all job which start at the curtime */
    3466 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
    3467
    3468 /* add the capacity requirments for all job which end at the curtime */
    3469 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
    3470
    3471 assert(freecapacity <= consdata->capacity);
    3472 assert(endindex <= nvars);
    3473
    3474 /* endindex - points to the next job which will finish */
    3475 /* j - points to the last job that has been released */
    3476
    3477 /* if free capacity is smaller than zero, then add branching candidates */
    3478 if( freecapacity < 0 && curtime >= hmin )
    3479 {
    3480 *timepoint = curtime;
    3481 break;
    3482 }
    3483 } /*lint --e{850}*/
    3484
    3485 /* free all buffer arrays */
    3486 SCIPfreeBufferArray(scip, &endindices);
    3487 SCIPfreeBufferArray(scip, &startindices);
    3488 SCIPfreeBufferArray(scip, &endtimes);
    3489 SCIPfreeBufferArray(scip, &starttimes);
    3490
    3491 return SCIP_OKAY;
    3492}
    3493
    3494/** checks all cumulative constraints for infeasibility and add branching candidates to storage */
    3495static
    3497 SCIP* scip, /**< SCIP data structure */
    3498 SCIP_CONS** conss, /**< constraints to be processed */
    3499 int nconss, /**< number of constraints */
    3500 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    3501 int* nbranchcands /**< pointer to store the number of branching variables */
    3502 )
    3503{
    3504 SCIP_HASHTABLE* collectedvars;
    3505 int c;
    3506
    3507 assert(scip != NULL);
    3508 assert(conss != NULL);
    3509
    3510 /* create a hash table */
    3512 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
    3513
    3514 assert(scip != NULL);
    3515 assert(conss != NULL);
    3516
    3517 for( c = 0; c < nconss; ++c )
    3518 {
    3519 SCIP_CONS* cons;
    3520 SCIP_CONSDATA* consdata;
    3521
    3522 int curtime;
    3523 int j;
    3524
    3525 cons = conss[c];
    3526 assert(cons != NULL);
    3527
    3528 if( !SCIPconsIsActive(cons) )
    3529 continue;
    3530
    3531 consdata = SCIPconsGetData(cons);
    3532 assert(consdata != NULL);
    3533
    3534 /* get point in time when capacity is exceeded */
    3535 SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
    3536
    3537 if( curtime < consdata->hmin || curtime >= consdata->hmax )
    3538 continue;
    3539
    3540 /* report all variables that are running at that point in time */
    3541 for( j = 0; j < consdata->nvars; ++j )
    3542 {
    3543 SCIP_VAR* var;
    3544 int lb;
    3545 int ub;
    3546
    3547 var = consdata->vars[j];
    3548 assert(var != NULL);
    3549
    3550 /* check if the variable was already added */
    3551 if( SCIPhashtableExists(collectedvars, (void*)var) )
    3552 continue;
    3553
    3556
    3557 if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
    3558 {
    3559 SCIP_Real solval;
    3560 SCIP_Real score;
    3561
    3562 solval = SCIPgetSolVal(scip, sol, var);
    3563 score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
    3564
    3565 SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
    3566 SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
    3567 (*nbranchcands)++;
    3568
    3569 SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
    3570 }
    3571 }
    3572 }
    3573
    3574 SCIPhashtableFree(&collectedvars);
    3575
    3576 SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
    3577
    3578 return SCIP_OKAY;
    3579}
    3580
    3581/** enforcement of an LP, pseudo, or relaxation solution */
    3582static
    3584 SCIP* scip, /**< SCIP data structure */
    3585 SCIP_CONS** conss, /**< constraints to be processed */
    3586 int nconss, /**< number of constraints */
    3587 SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
    3588 SCIP_Bool branch, /**< should branching candidates be collected */
    3589 SCIP_RESULT* result /**< pointer to store the result */
    3590 )
    3591{
    3592 if( branch )
    3593 {
    3594 int nbranchcands;
    3595
    3596 nbranchcands = 0;
    3597 SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
    3598
    3599 if( nbranchcands > 0 )
    3600 (*result) = SCIP_INFEASIBLE;
    3601 }
    3602 else
    3603 {
    3604 SCIP_Bool violated;
    3605 int c;
    3606
    3607 violated = FALSE;
    3608
    3609 /* first check if a constraints is violated */
    3610 for( c = 0; c < nconss && !violated; ++c )
    3611 {
    3612 SCIP_CONS* cons;
    3613
    3614 cons = conss[c];
    3615 assert(cons != NULL);
    3616
    3617 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
    3618 }
    3619
    3620 if( violated )
    3621 (*result) = SCIP_INFEASIBLE;
    3622 }
    3623
    3624 return SCIP_OKAY;
    3625}
    3626
    3627/**@} */
    3628
    3629/**@name Propagation
    3630 *
    3631 * @{
    3632 */
    3633
    3634/** check if cumulative constraint is independently of all other constraints */
    3635static
    3637 SCIP_CONS* cons /**< cumulative constraint */
    3638 )
    3639{
    3640 SCIP_CONSDATA* consdata;
    3641 SCIP_VAR** vars;
    3642 SCIP_Bool* downlocks;
    3643 SCIP_Bool* uplocks;
    3644 int nvars;
    3645 int v;
    3646
    3647 consdata = SCIPconsGetData(cons);
    3648 assert(consdata != NULL);
    3649
    3650 nvars = consdata->nvars;
    3651 vars = consdata->vars;
    3652 downlocks = consdata->downlocks;
    3653 uplocks = consdata->uplocks;
    3654
    3655 /* check if the cumulative constraint has the only locks on the involved variables */
    3656 for( v = 0; v < nvars; ++v )
    3657 {
    3658 SCIP_VAR* var;
    3659
    3660 var = vars[v];
    3661 assert(var != NULL);
    3662
    3663 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
    3664 || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
    3665 return FALSE;
    3666 }
    3667
    3668 return TRUE;
    3669}
    3670
    3671/** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
    3672 * (dual reductions)
    3673 */
    3674static
    3676 SCIP* scip, /**< SCIP data structure */
    3677 SCIP_CONS* cons, /**< cumulative constraint */
    3678 SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
    3679 int* nchgbds, /**< pointer to store the number changed variable bounds */
    3680 int* nfixedvars, /**< pointer to count number of fixings */
    3681 int* ndelconss, /**< pointer to count number of deleted constraints */
    3682 SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
    3683 SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
    3684 )
    3685{
    3686 SCIP_CONSDATA* consdata;
    3687 SCIP_VAR** vars;
    3688 SCIP_Real* objvals;
    3689 SCIP_Real* lbs;
    3690 SCIP_Real* ubs;
    3691 SCIP_Real timelimit;
    3692 SCIP_Real memorylimit;
    3693 SCIP_Bool solved;
    3694 SCIP_Bool error;
    3695
    3696 int ncheckconss;
    3697 int nvars;
    3698 int v;
    3699
    3700 assert(scip != NULL);
    3701 assert(!SCIPconsIsModifiable(cons));
    3702 assert(SCIPgetNConss(scip) > 0);
    3703
    3704 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
    3705 * would/could end in an implication which can lead to cutoff of the/all optimal solution
    3706 */
    3708 return SCIP_OKAY;
    3709
    3710 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
    3711 * use the locks to decide for a dual reduction using this constraint;
    3712 */
    3713 if( !SCIPconsIsChecked(cons) )
    3714 return SCIP_OKAY;
    3715
    3716 ncheckconss = SCIPgetNCheckConss(scip);
    3717
    3718 /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
    3719 * presolved problem do nothing execpt to change the parameter settings
    3720 */
    3721 if( ncheckconss == 1 )
    3722 {
    3723 /* shrink the minimal maximum value for the conflict length */
    3724 SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
    3725
    3726 /* use only first unique implication point */
    3727 SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
    3728
    3729 /* do not use reconversion conflicts */
    3730 SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
    3731
    3732 /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
    3733 SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
    3734
    3735 /* increase the number of conflicts which induce a restart */
    3736 SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
    3737
    3738 /* weight the variable which made into a conflict */
    3739 SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
    3740
    3741 /* do not check pseudo solution (for performance reasons) */
    3742 SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
    3743
    3744 /* use value based history to detect a reasonable branching point */
    3745 SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
    3746
    3747 /* turn of LP relaxation */
    3748 SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
    3749
    3750 /* prefer the down branch in case the value based history does not suggest something */
    3751 SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
    3752
    3753 /* accept any bound change */
    3754 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
    3755
    3756 /* allow for at most 10 restart, after that the value based history should be reliable */
    3757 SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
    3758
    3759 /* set priority for depth first search to highest possible value */
    3760 SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
    3761
    3762 return SCIP_OKAY;
    3763 }
    3764
    3765 consdata = SCIPconsGetData(cons);
    3766 assert(consdata != NULL);
    3767
    3768 /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
    3769 * fail on the first place
    3770 */
    3771 if( consdata->triedsolving )
    3772 return SCIP_OKAY;
    3773
    3774 /* check if constraint is independently */
    3775 if( !isConsIndependently(cons) )
    3776 return SCIP_OKAY;
    3777
    3778 /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
    3779 * constraint is deleted; otherwise, we want to ensure that we do not try that again
    3780 */
    3781 consdata->triedsolving = TRUE;
    3782
    3783 SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
    3786
    3787 nvars = consdata->nvars;
    3788 vars = consdata->vars;
    3789
    3790 SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
    3791 SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
    3792 SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
    3793
    3794 for( v = 0; v < nvars; ++v )
    3795 {
    3796 SCIP_VAR* var;
    3797
    3798 /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
    3799 * array
    3800 */
    3801 var = vars[v];
    3802 assert(var != NULL);
    3803
    3804 lbs[v] = SCIPvarGetLbLocal(var);
    3805 ubs[v] = SCIPvarGetUbLocal(var);
    3806
    3807 objvals[v] = SCIPvarGetObj(var);
    3808 }
    3809
    3810 /* check whether there is enough time and memory left */
    3811 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
    3812 if( !SCIPisInfinity(scip, timelimit) )
    3813 timelimit -= SCIPgetSolvingTime(scip);
    3814 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
    3815
    3816 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
    3817 if( !SCIPisInfinity(scip, memorylimit) )
    3818 {
    3819 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
    3820 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
    3821 }
    3822
    3823 /* solve the cumulative condition separately */
    3824 SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
    3825 consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
    3826
    3827 if( !(*cutoff) && !(*unbounded) && !error )
    3828 {
    3829 SCIP_Bool infeasible;
    3830 SCIP_Bool tightened;
    3831 SCIP_Bool allfixed;
    3832
    3833 allfixed = TRUE;
    3834
    3835 for( v = 0; v < nvars; ++v )
    3836 {
    3837 /* check if variable is fixed */
    3838 if( lbs[v] + 0.5 > ubs[v] )
    3839 {
    3840 SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
    3841 assert(!infeasible);
    3842
    3843 if( tightened )
    3844 {
    3845 (*nfixedvars)++;
    3846 consdata->triedsolving = FALSE;
    3847 }
    3848 }
    3849 else
    3850 {
    3851 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
    3852 assert(!infeasible);
    3853
    3854 if( tightened )
    3855 {
    3856 (*nchgbds)++;
    3857 consdata->triedsolving = FALSE;
    3858 }
    3859
    3860 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
    3861 assert(!infeasible);
    3862
    3863 if( tightened )
    3864 {
    3865 (*nchgbds)++;
    3866 consdata->triedsolving = FALSE;
    3867 }
    3868
    3869 allfixed = FALSE;
    3870 }
    3871 }
    3872
    3873 /* if all variables are fixed, remove the cumulative constraint since it is redundant */
    3874 if( allfixed )
    3875 {
    3877 (*ndelconss)++;
    3878 }
    3879 }
    3880
    3881 SCIPfreeBufferArray(scip, &objvals);
    3884
    3885 return SCIP_OKAY;
    3886}
    3887
    3888/** start conflict analysis to analysis the core insertion which is infeasible */
    3889static
    3891 SCIP* scip, /**< SCIP data structure */
    3892 int nvars, /**< number of start time variables (activities) */
    3893 SCIP_VAR** vars, /**< array of start time variables */
    3894 int* durations, /**< array of durations */
    3895 int* demands, /**< array of demands */
    3896 int capacity, /**< cumulative capacity */
    3897 int hmin, /**< left bound of time axis to be considered (including hmin) */
    3898 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    3899 SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
    3900 int inferduration, /**< duration of the start time variable */
    3901 int inferdemand, /**< demand of the start time variable */
    3902 int inferpeak, /**< profile preak which causes the infeasibilty */
    3903 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    3904 SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
    3905 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    3906 )
    3907{
    3908 SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
    3909 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
    3910 SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
    3911
    3912 /* initialize conflict analysis if conflict analysis is applicable */
    3914 {
    3916
    3917 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    3918 infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
    3919
    3920 SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
    3921
    3922 /* add both bound of the inference variable since these biuld the core which we could not inserted */
    3923 if( usebdwidening )
    3924 {
    3925 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
    3926 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
    3927 }
    3928 else
    3929 {
    3930 SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
    3931 SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
    3932 }
    3933
    3934 *initialized = TRUE;
    3935 }
    3936
    3937 return SCIP_OKAY;
    3938}
    3939
    3940/** We are using the core resource profile which contains all core except the one of the start time variable which we
    3941 * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
    3942 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
    3943 * analysis
    3944 */
    3945static
    3947 SCIP* scip, /**< SCIP data structure */
    3948 int nvars, /**< number of start time variables (activities) */
    3949 SCIP_VAR** vars, /**< array of start time variables */
    3950 int* durations, /**< array of durations */
    3951 int* demands, /**< array of demands */
    3952 int capacity, /**< cumulative capacity */
    3953 int hmin, /**< left bound of time axis to be considered (including hmin) */
    3954 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    3955 SCIP_CONS* cons, /**< constraint which is propagated */
    3956 SCIP_PROFILE* profile, /**< resource profile */
    3957 int idx, /**< position of the variable to propagate */
    3958 int* nchgbds, /**< pointer to store the number of bound changes */
    3959 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    3960 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    3961 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    3962 SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
    3963 )
    3964{
    3965 SCIP_VAR* var;
    3966 int ntimepoints;
    3967 int duration;
    3968 int demand;
    3969 int peak;
    3970 int newlb;
    3971 int est;
    3972 int lst;
    3973 int pos;
    3974
    3975 var = vars[idx];
    3976 assert(var != NULL);
    3977
    3978 duration = durations[idx];
    3979 assert(duration > 0);
    3980
    3981 demand = demands[idx];
    3982 assert(demand > 0);
    3983
    3986 ntimepoints = SCIPprofileGetNTimepoints(profile);
    3987
    3988 /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
    3989 * load which we have at the earliest start time (lower bound)
    3990 */
    3991 (void) SCIPprofileFindLeft(profile, est, &pos);
    3992
    3993 SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
    3994
    3995 /* we now trying to move the earliest start time in steps of at most "duration" length */
    3996 do
    3997 {
    3998 INFERINFO inferinfo;
    3999 SCIP_Bool tightened;
    4000 int ect;
    4001
    4002#ifndef NDEBUG
    4003 {
    4004 /* in debug mode we check that we adjust the search position correctly */
    4005 int tmppos;
    4006
    4007 (void)SCIPprofileFindLeft(profile, est, &tmppos);
    4008 assert(pos == tmppos);
    4009 }
    4010#endif
    4011 ect = est + duration;
    4012 peak = -1;
    4013
    4014 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
    4015 * want a peak which is closest to the earliest completion time
    4016 */
    4017 do
    4018 {
    4019 /* check if the profile load conflicts with the demand of the start time variable */
    4020 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
    4021 peak = pos;
    4022
    4023 pos++;
    4024 }
    4025 while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
    4026
    4027 /* if we found no peak that means current the job could be scheduled at its earliest start time without
    4028 * conflicting to the core resource profile
    4029 */
    4030 /* coverity[check_after_sink] */
    4031 if( peak == -1 )
    4032 break;
    4033
    4034 /* the peak position gives us a time point where the start time variable is in conflict with the resource
    4035 * profile. That means we have to move it to the next time point in the resource profile but at most to the
    4036 * earliest completion time (the remaining move will done in the next loop)
    4037 */
    4038 newlb = SCIPprofileGetTime(profile, peak+1);
    4039 newlb = MIN(newlb, ect);
    4040
    4041 /* if the earliest start time is greater than the lst we detected an infeasibilty */
    4042 if( newlb > lst )
    4043 {
    4044 SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
    4045
    4046 /* use conflict analysis to analysis the core insertion which was infeasible */
    4047 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    4048 var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
    4049
    4050 if( explanation != NULL )
    4051 explanation[idx] = TRUE;
    4052
    4053 *infeasible = TRUE;
    4054
    4055 break;
    4056 }
    4057
    4058 /* construct the inference information which we are using with the conflict analysis to resolve that particular
    4059 * bound change
    4060 */
    4061 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
    4062
    4063 /* perform the bound lower bound change */
    4064 if( inferInfoIsValid(inferinfo) )
    4065 {
    4066 SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
    4067 }
    4068 else
    4069 {
    4070 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
    4071 }
    4072 assert(tightened);
    4073 assert(!(*infeasible));
    4074
    4075 SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
    4076 (*nchgbds)++;
    4077
    4078 /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
    4080
    4081 /* adjust the earliest start time
    4082 *
    4083 * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
    4084 * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
    4085 * involved.
    4086 */
    4088 assert(est >= newlb);
    4089
    4090 /* adjust the search position for the resource profile for the next step */
    4091 if( est == SCIPprofileGetTime(profile, peak+1) )
    4092 pos = peak + 1;
    4093 else
    4094 pos = peak;
    4095 }
    4096 while( est < lst );
    4097
    4098 return SCIP_OKAY;
    4099}
    4100
    4101/** We are using the core resource profile which contains all core except the one of the start time variable which we
    4102 * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
    4103 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
    4104 * analysis
    4105 */
    4106static
    4108 SCIP* scip, /**< SCIP data structure */
    4109 SCIP_VAR* var, /**< start time variable to propagate */
    4110 int duration, /**< duration of the job */
    4111 int demand, /**< demand of the job */
    4112 int capacity, /**< cumulative capacity */
    4113 SCIP_CONS* cons, /**< constraint which is propagated */
    4114 SCIP_PROFILE* profile, /**< resource profile */
    4115 int idx, /**< position of the variable to propagate */
    4116 int* nchgbds /**< pointer to store the number of bound changes */
    4117 )
    4118{
    4119 int ntimepoints;
    4120 int newub;
    4121 int peak;
    4122 int pos;
    4123 int est;
    4124 int lst;
    4125 int lct;
    4126
    4127 assert(var != NULL);
    4128 assert(duration > 0);
    4129 assert(demand > 0);
    4130
    4133
    4134 /* in case the start time variable is fixed do nothing */
    4135 if( est == lst )
    4136 return SCIP_OKAY;
    4137
    4138 ntimepoints = SCIPprofileGetNTimepoints(profile);
    4139
    4140 lct = lst + duration;
    4141
    4142 /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
    4143 * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
    4144 * position gives us the load which we have at the latest completion time minus one
    4145 */
    4146 (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
    4147
    4148 SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
    4150
    4151 if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
    4152 return SCIP_OKAY;
    4153
    4154 /* we now trying to move the latest start time in steps of at most "duration" length */
    4155 do
    4156 {
    4157 INFERINFO inferinfo;
    4158 SCIP_Bool tightened;
    4159 SCIP_Bool infeasible;
    4160
    4161 peak = -1;
    4162
    4163#ifndef NDEBUG
    4164 {
    4165 /* in debug mode we check that we adjust the search position correctly */
    4166 int tmppos;
    4167
    4168 (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
    4169 assert(pos == tmppos);
    4170 }
    4171#endif
    4172
    4173 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
    4174 * want a peak which is closest to the latest start time
    4175 */
    4176 do
    4177 {
    4178 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
    4179 peak = pos;
    4180
    4181 pos--;
    4182 }
    4183 while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
    4184
    4185 /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
    4186 * to the core resource profile
    4187 */
    4188 /* coverity[check_after_sink] */
    4189 if( peak == -1 )
    4190 break;
    4191
    4192 /* the peak position gives us a time point where the start time variable is in conflict with the resource
    4193 * profile. That means the job has be done until that point. Hence that gives us the latest completion
    4194 * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
    4195 * doing in the next loop)
    4196 */
    4197 newub = SCIPprofileGetTime(profile, peak);
    4198 newub = MAX(newub, lst) - duration;
    4199 assert(newub >= est);
    4200
    4201 /* construct the inference information which we are using with the conflict analysis to resolve that particular
    4202 * bound change
    4203 */
    4204 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
    4205
    4206 /* perform the bound upper bound change */
    4207 if( inferInfoIsValid(inferinfo) )
    4208 {
    4209 SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
    4210 }
    4211 else
    4212 {
    4213 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
    4214 }
    4215 assert(tightened);
    4216 assert(!infeasible);
    4217
    4218 SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
    4219 (*nchgbds)++;
    4220
    4221 /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
    4223
    4224 /* adjust the latest start and completion time
    4225 *
    4226 * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
    4227 * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
    4228 * involved.
    4229 */
    4231 assert(lst <= newub);
    4232 lct = lst + duration;
    4233
    4234 /* adjust the search position for the resource profile for the next step */
    4235 if( SCIPprofileGetTime(profile, peak) == lct )
    4236 pos = peak - 1;
    4237 else
    4238 pos = peak;
    4239 }
    4240 while( est < lst );
    4241
    4242 return SCIP_OKAY;
    4243}
    4244
    4245/** compute for the different earliest start and latest completion time the core energy of the corresponding time
    4246 * points
    4247 */
    4248static
    4250 SCIP_PROFILE* profile, /**< core profile */
    4251 int nvars, /**< number of start time variables (activities) */
    4252 int* ests, /**< array of sorted earliest start times */
    4253 int* lcts, /**< array of sorted latest completion times */
    4254 int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
    4255 int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
    4256 )
    4257{
    4258 int ntimepoints;
    4259 int energy;
    4260 int t;
    4261 int v;
    4262
    4263 ntimepoints = SCIPprofileGetNTimepoints(profile);
    4264 t = ntimepoints - 1;
    4265 energy = 0;
    4266
    4267 /* compute core energy after the earliest start time of each job */
    4268 for( v = nvars-1; v >= 0; --v )
    4269 {
    4270 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
    4271 {
    4272 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
    4273 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
    4274 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
    4275 t--;
    4276 }
    4277 assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
    4278
    4279 /* maybe ests[j] is in-between two timepoints */
    4280 if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
    4281 {
    4282 assert(t > 0);
    4283 coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
    4284 }
    4285 else
    4286 coreEnergyAfterEst[v] = energy;
    4287 }
    4288
    4289 t = ntimepoints - 1;
    4290 energy = 0;
    4291
    4292 /* compute core energy after the latest completion time of each job */
    4293 for( v = nvars-1; v >= 0; --v )
    4294 {
    4295 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
    4296 {
    4297 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
    4298 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
    4299 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
    4300 t--;
    4301 }
    4302 assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
    4303
    4304 /* maybe lcts[j] is in-between two timepoints */
    4305 if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
    4306 {
    4307 assert(t > 0);
    4308 coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
    4309 }
    4310 else
    4311 coreEnergyAfterLct[v] = energy;
    4312 }
    4313}
    4314
    4315/** collect earliest start times, latest completion time, and free energy contributions */
    4316static
    4318 SCIP* scip, /**< SCIP data structure */
    4319 int nvars, /**< number of start time variables (activities) */
    4320 SCIP_VAR** vars, /**< array of start time variables */
    4321 int* durations, /**< array of durations */
    4322 int* demands, /**< array of demands */
    4323 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4324 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4325 int* permests, /**< array to store the variable positions */
    4326 int* ests, /**< array to store earliest start times */
    4327 int* permlcts, /**< array to store the variable positions */
    4328 int* lcts, /**< array to store latest completion times */
    4329 int* ects, /**< array to store earliest completion times of the flexible part of the job */
    4330 int* lsts, /**< array to store latest start times of the flexible part of the job */
    4331 int* flexenergies /**< array to store the flexible energies of each job */
    4332 )
    4333{
    4334 int v;
    4335
    4336 for( v = 0; v < nvars; ++ v)
    4337 {
    4338 int duration;
    4339 int leftadjust;
    4340 int rightadjust;
    4341 int core;
    4342 int est;
    4343 int lct;
    4344 int ect;
    4345 int lst;
    4346
    4347 duration = durations[v];
    4348 assert(duration > 0);
    4349
    4352 ect = est + duration;
    4353 lct = lst + duration;
    4354
    4355 ests[v] = est;
    4356 lcts[v] = lct;
    4357 permests[v] = v;
    4358 permlcts[v] = v;
    4359
    4360 /* compute core time window which lies within the effective horizon */
    4361 core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
    4362
    4363 /* compute the number of time steps the job could run before the effective horizon */
    4364 leftadjust = MAX(0, hmin - est);
    4365
    4366 /* compute the number of time steps the job could run after the effective horizon */
    4367 rightadjust = MAX(0, lct - hmax);
    4368
    4369 /* compute for each job the energy which is flexible; meaning not part of the core */
    4370 flexenergies[v] = duration - leftadjust - rightadjust - core;
    4371 flexenergies[v] = MAX(0, flexenergies[v]);
    4372 flexenergies[v] *= demands[v];
    4373 assert(flexenergies[v] >= 0);
    4374
    4375 /* the earliest completion time of the flexible energy */
    4376 ects[v] = MIN(ect, lst);
    4377
    4378 /* the latest start time of the flexible energy */
    4379 lsts[v] = MAX(ect, lst);
    4380 }
    4381}
    4382
    4383/** try to tighten the lower bound of the given variable */
    4384static
    4386 SCIP* scip, /**< SCIP data structure */
    4387 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4388 int nvars, /**< number of start time variables (activities) */
    4389 SCIP_VAR** vars, /**< array of start time variables */
    4390 int* durations, /**< array of durations */
    4391 int* demands, /**< array of demands */
    4392 int capacity, /**< cumulative capacity */
    4393 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4394 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4395 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
    4396 int duration, /**< duration of the job */
    4397 int demand, /**< demand of the job */
    4398 int est, /**< earliest start time of the job */
    4399 int ect, /**< earliest completion time of the flexible part of the job */
    4400 int lct, /**< latest completion time of the job */
    4401 int begin, /**< begin of the time window under investigation */
    4402 int end, /**< end of the time window under investigation */
    4403 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
    4404 int* bestlb, /**< pointer to strope the best lower bound change */
    4405 int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
    4406 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    4407 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    4408 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    4409 )
    4410{
    4411 int newlb;
    4412
    4413 assert(begin >= hmin);
    4414 assert(end <= hmax);
    4415
    4416 /* check if the time-table edge-finding should infer bounds */
    4417 if( !conshdlrdata->ttefinfer )
    4418 return SCIP_OKAY;
    4419
    4420 /* if the job can be processed completely before or after the time window, nothing can be tightened */
    4421 if( est >= end || ect <= begin )
    4422 return SCIP_OKAY;
    4423
    4424 /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
    4425 * skip since the overload check will do the job
    4426 */
    4427 if( est >= begin && ect <= end )
    4428 return SCIP_OKAY;
    4429
    4430 /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
    4431 * earliest start time
    4432 */
    4433 if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
    4434 return SCIP_OKAY;
    4435
    4436 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
    4437 * present; therefore, we need to add the core;
    4438 *
    4439 * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
    4440 * compute the earliest completion time of the (whole) job
    4441 */
    4442 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
    4443
    4444 /* compute a latest start time (upper bound) such that the job consums at most the available energy
    4445 *
    4446 * @note we can round down the compute duration w.r.t. the available energy
    4447 */
    4448 newlb = end - (int) (energy / demand);
    4449
    4450 /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
    4451 * bound (latest start time); meaning it is not possible to schedule the job
    4452 */
    4453 if( newlb > lct - duration )
    4454 {
    4455 /* initialize conflict analysis if conflict analysis is applicable */
    4457 {
    4458 SCIP_Real relaxedbd;
    4459
    4460 assert(boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
    4461
    4462 /* it is enough to overshoot the upper bound of the variable by one */
    4463 relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
    4464
    4465 /* initialize conflict analysis */
    4467
    4468 /* added to upper bound (which was overcut be new lower bound) of the variable */
    4470
    4471 /* analyze the infeasible */
    4472 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    4473 begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
    4474
    4475 (*initialized) = TRUE;
    4476 }
    4477
    4478 (*cutoff) = TRUE;
    4479 }
    4480 else if( newlb > (*bestlb) )
    4481 {
    4482 INFERINFO inferinfo;
    4483
    4484 assert(newlb > begin);
    4485
    4486 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
    4487
    4488 /* construct inference information */
    4489 (*inferinfos) = inferInfoToInt(inferinfo);
    4490 (*bestlb) = newlb;
    4491 }
    4492
    4493 return SCIP_OKAY;
    4494}
    4495
    4496/** try to tighten the upper bound of the given variable */
    4497static
    4499 SCIP* scip, /**< SCIP data structure */
    4500 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4501 int nvars, /**< number of start time variables (activities) */
    4502 SCIP_VAR** vars, /**< array of start time variables */
    4503 int* durations, /**< array of durations */
    4504 int* demands, /**< array of demands */
    4505 int capacity, /**< cumulative capacity */
    4506 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4507 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4508 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
    4509 int duration, /**< duration of the job */
    4510 int demand, /**< demand of the job */
    4511 int est, /**< earliest start time of the job */
    4512 int lst, /**< latest start time of the flexible part of the job */
    4513 int lct, /**< latest completion time of the job */
    4514 int begin, /**< begin of the time window under investigation */
    4515 int end, /**< end of the time window under investigation */
    4516 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
    4517 int* bestub, /**< pointer to strope the best upper bound change */
    4518 int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
    4519 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    4520 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    4521 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    4522 )
    4523{
    4524 int newub;
    4525
    4526 assert(begin >= hmin);
    4527 assert(end <= hmax);
    4528 assert(est < begin);
    4529
    4530 /* check if the time-table edge-finding should infer bounds */
    4531 if( !conshdlrdata->ttefinfer )
    4532 return SCIP_OKAY;
    4533
    4534 /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
    4535 if( lst >= end || lct <= begin )
    4536 return SCIP_OKAY;
    4537
    4538 /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
    4539 * skip since the overload check will do the job
    4540 */
    4541 if( lst >= begin && lct <= end )
    4542 return SCIP_OKAY;
    4543
    4544 /* check if the available energy in the time window is to small to handle the flexible part of the job */
    4545 if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
    4546 return SCIP_OKAY;
    4547
    4548 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
    4549 * present; therefore, we need to add the core;
    4550 *
    4551 * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
    4552 * latest start of the (whole) job
    4553 */
    4554 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
    4555 assert(energy >= 0);
    4556
    4557 /* compute a latest start time (upper bound) such that the job consums at most the available energy
    4558 *
    4559 * @note we can round down the compute duration w.r.t. the available energy
    4560 */
    4561 assert(demand > 0);
    4562 newub = begin - duration + (int) (energy / demand);
    4563
    4564 /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
    4565 * bound (earliest start time); meaning it is not possible to schedule the job
    4566 */
    4567 if( newub < est )
    4568 {
    4569 /* initialize conflict analysis if conflict analysis is applicable */
    4571 {
    4572 SCIP_Real relaxedbd;
    4573
    4574 assert(boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
    4575
    4576 /* it is enough to undershoot the lower bound of the variable by one */
    4577 relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
    4578
    4579 /* initialize conflict analysis */
    4581
    4582 /* added to lower bound (which was undercut be new upper bound) of the variable */
    4584
    4585 /* analyze the infeasible */
    4586 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    4587 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
    4588
    4589 (*initialized) = TRUE;
    4590 }
    4591
    4592 (*cutoff) = TRUE;
    4593 }
    4594 else if( newub < (*bestub) )
    4595 {
    4596 INFERINFO inferinfo;
    4597
    4598 assert(newub < begin);
    4599
    4600 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
    4601
    4602 /* construct inference information */
    4603 (*inferinfos) = inferInfoToInt(inferinfo);
    4604 (*bestub) = newub;
    4605 }
    4606
    4607 return SCIP_OKAY;
    4608}
    4609
    4610/** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
    4611static
    4613 SCIP* scip, /**< SCIP data structure */
    4614 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4615 int nvars, /**< number of start time variables (activities) */
    4616 SCIP_VAR** vars, /**< array of start time variables */
    4617 int* durations, /**< array of durations */
    4618 int* demands, /**< array of demands */
    4619 int capacity, /**< cumulative capacity */
    4620 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4621 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4622 int* newlbs, /**< array to buffer new lower bounds */
    4623 int* newubs, /**< array to buffer new upper bounds */
    4624 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
    4625 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
    4626 int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
    4627 int* flexenergies, /**< array of flexible energies in the same order as the variables */
    4628 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
    4629 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
    4630 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
    4631 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
    4632 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
    4633 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    4634 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    4635 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    4636 )
    4637{
    4638 int coreEnergyAfterEnd;
    4639 SCIP_Longint maxavailable;
    4640 SCIP_Longint minavailable;
    4641 SCIP_Longint totalenergy;
    4642 int nests;
    4643 int est;
    4644 int lct;
    4645 int start;
    4646 int end;
    4647 int v;
    4648
    4649 est = INT_MAX;
    4650 lct = INT_MIN;
    4651
    4652 /* compute earliest start and latest completion time of all jobs */
    4653 for( v = 0; v < nvars; ++v )
    4654 {
    4656 end = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
    4657
    4658 est = MIN(est, start);
    4659 lct = MAX(lct, end);
    4660 }
    4661
    4662 /* adjust the effective time horizon */
    4663 hmin = MAX(hmin, est);
    4664 hmax = MIN(hmax, lct);
    4665
    4666 end = hmax + 1;
    4667 coreEnergyAfterEnd = -1;
    4668
    4669 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
    4670 minavailable = maxavailable;
    4671 totalenergy = computeTotalEnergy(durations, demands, nvars);
    4672
    4673 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
    4674 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
    4675 return SCIP_OKAY;
    4676
    4677 nests = nvars;
    4678
    4679 /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
    4680 * times define the end of the time interval under investigation
    4681 */
    4682 for( v = nvars-1; v >= 0 && !(*cutoff); --v )
    4683 {
    4684 int flexenergy;
    4685 int minbegin;
    4686 int lbenergy;
    4687 int lbcand;
    4688 int i;
    4689
    4690 lct = lcts[v];
    4691
    4692 /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
    4693 * infinity capacity is available; hence we skip that
    4694 */
    4695 if( lct > hmax )
    4696 continue;
    4697
    4698 /* if the latest completion time is smaller then hmin we have to stop */
    4699 if( lct <= hmin )
    4700 {
    4701 assert(v == 0 || lcts[v-1] <= lcts[v]);
    4702 break;
    4703 }
    4704
    4705 /* if the latest completion time equals to previous end time, we can continue since this particular interval
    4706 * induced by end was just analyzed
    4707 */
    4708 if( lct == end )
    4709 continue;
    4710
    4711 assert(lct < end);
    4712
    4713 /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
    4714 * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
    4715 * free energy; if so it means that in the next iterate the free-energy cannot be negative
    4716 */
    4717 if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
    4718 {
    4719 SCIP_Longint freeenergy;
    4720
    4721 assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
    4722 assert(coreEnergyAfterEnd >= 0);
    4723
    4724 /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
    4725 freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
    4726
    4727 if( freeenergy <= minavailable )
    4728 {
    4729 SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
    4730 continue;
    4731 }
    4732 }
    4733
    4734 SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
    4735
    4736 end = lct;
    4737 coreEnergyAfterEnd = coreEnergyAfterLct[v];
    4738
    4739 flexenergy = 0;
    4740 minavailable = maxavailable;
    4741 minbegin = hmax;
    4742 lbcand = -1;
    4743 lbenergy = 0;
    4744
    4745 /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
    4746 * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
    4747 * wider
    4748 */
    4749 for( i = nests-1; i >= 0; --i )
    4750 {
    4751 SCIP_VAR* var;
    4752 SCIP_Longint freeenergy;
    4753 int duration;
    4754 int demand;
    4755 int begin;
    4756 int idx;
    4757 int lst;
    4758
    4759 idx = perm[i];
    4760 assert(idx >= 0);
    4761 assert(idx < nvars);
    4762 assert(!(*cutoff));
    4763
    4764 /* the earliest start time of the job */
    4765 est = ests[i];
    4766
    4767 /* if the job starts after the current end, we can skip it and do not need to consider it again since the
    4768 * latest completion times (which define end) are scant in non-increasing order
    4769 */
    4770 if( end <= est )
    4771 {
    4772 nests--;
    4773 continue;
    4774 }
    4775
    4776 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
    4777 * current ending time
    4778 */
    4779 if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
    4780 break;
    4781
    4782 var = vars[idx];
    4783 assert(var != NULL);
    4784
    4785 duration = durations[idx];
    4786 assert(duration > 0);
    4787
    4788 demand = demands[idx];
    4789 assert(demand > 0);
    4790
    4791 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
    4792
    4793 /* the latest start time of the free part of the job */
    4794 lst = lsts[idx];
    4795
    4796 /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
    4797 * investigation; hence the overload check will do the the job
    4798 */
    4799 assert(est <= minbegin);
    4800 if( minavailable < maxavailable && est < minbegin )
    4801 {
    4802 assert(!(*cutoff));
    4803
    4804 /* try to tighten the upper bound */
    4805 SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    4806 var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
    4807 initialized, explanation, cutoff) );
    4808
    4809 if( *cutoff )
    4810 break;
    4811 }
    4812
    4813 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
    4814 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
    4815
    4816 begin = est;
    4817 assert(boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
    4818
    4819 /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
    4820 * free energy
    4821 */
    4822 if( begin < hmin )
    4823 break;
    4824
    4825 /* compute the contribution to the flexible energy */
    4826 if( lct <= end )
    4827 {
    4828 /* if the jobs has to finish before the end, all the energy has to be scheduled */
    4829 assert(lst >= begin);
    4830 assert(flexenergies[idx] >= 0);
    4831 flexenergy += flexenergies[idx];
    4832 }
    4833 else
    4834 {
    4835 /* the job partly overlaps with the end */
    4836 int candenergy;
    4837 int energy;
    4838
    4839 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
    4840 * w.r.t. latest start time
    4841 *
    4842 * @note we need to be aware of the effective horizon
    4843 */
    4844 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
    4845 assert(end - lst < duration);
    4846 assert(energy >= 0);
    4847
    4848 /* adjust the flexible energy of the time interval */
    4849 flexenergy += energy;
    4850
    4851 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
    4852 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
    4853 assert(candenergy >= 0);
    4854
    4855 /* check if we found a better candidate */
    4856 if( candenergy > lbenergy )
    4857 {
    4858 lbenergy = candenergy;
    4859 lbcand = idx;
    4860 }
    4861 }
    4862
    4863 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
    4864 assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
    4865
    4866 /* compute the energy which is not used yet */
    4867 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
    4868
    4869 /* check overload */
    4870 if( freeenergy < 0 )
    4871 {
    4872 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
    4873
    4874 /* initialize conflict analysis if conflict analysis is applicable */
    4876 {
    4877 /* analyze infeasibilty */
    4879
    4880 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    4882 conshdlrdata->usebdwidening, explanation) );
    4883
    4884 (*initialized) = TRUE;
    4885 }
    4886
    4887 (*cutoff) = TRUE;
    4888
    4889 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
    4891
    4892 break;
    4893 }
    4894
    4895 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
    4896 if( lbenergy > 0 && freeenergy < lbenergy )
    4897 {
    4898 SCIP_Longint energy;
    4899 int newlb;
    4900 int ect;
    4901
    4902 ect = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
    4903 lst = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
    4904
    4905 /* remove the energy of our job from the ... */
    4906 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
    4907
    4908 newlb = end - (int)(energy / demands[lbcand]);
    4909
    4910 if( newlb > lst )
    4911 {
    4912 /* initialize conflict analysis if conflict analysis is applicable */
    4914 {
    4915 SCIP_Real relaxedbd;
    4916
    4917 /* analyze infeasibilty */
    4919
    4920 relaxedbd = lst + 1.0;
    4921
    4922 /* added to upper bound (which was overcut be new lower bound) of the variable */
    4923 SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
    4924
    4925 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    4926 begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
    4927 conshdlrdata->usebdwidening, explanation) );
    4928
    4929 (*initialized) = TRUE;
    4930 }
    4931
    4932 (*cutoff) = TRUE;
    4933 break;
    4934 }
    4935 else if( newlb > newlbs[lbcand] )
    4936 {
    4937 INFERINFO inferinfo;
    4938
    4939 /* construct inference information */
    4940 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
    4941
    4942 /* buffer upper bound change */
    4943 lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
    4944 newlbs[lbcand] = newlb;
    4945 }
    4946 }
    4947
    4948 /* check if the current interval has a smaller free energy */
    4949 if( minavailable > freeenergy )
    4950 {
    4951 minavailable = freeenergy;
    4952 minbegin = begin;
    4953 }
    4954 assert(minavailable >= 0);
    4955 }
    4956 }
    4957
    4958 return SCIP_OKAY;
    4959}
    4960
    4961/** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
    4962static
    4964 SCIP* scip, /**< SCIP data structure */
    4965 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4966 int nvars, /**< number of start time variables (activities) */
    4967 SCIP_VAR** vars, /**< array of start time variables */
    4968 int* durations, /**< array of durations */
    4969 int* demands, /**< array of demands */
    4970 int capacity, /**< cumulative capacity */
    4971 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4972 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4973 int* newlbs, /**< array to buffer new lower bounds */
    4974 int* newubs, /**< array to buffer new upper bounds */
    4975 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
    4976 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
    4977 int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
    4978 int* flexenergies, /**< array of flexible energies in the same order as the variables */
    4979 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
    4980 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
    4981 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
    4982 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
    4983 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
    4984 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    4985 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    4986 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    4987 )
    4988{
    4989 int coreEnergyAfterStart;
    4990 SCIP_Longint maxavailable;
    4991 SCIP_Longint minavailable;
    4992 SCIP_Longint totalenergy;
    4993 int nlcts;
    4994 int begin;
    4995 int minest;
    4996 int maxlct;
    4997 int start;
    4998 int end;
    4999 int v;
    5000
    5001 if( *cutoff )
    5002 return SCIP_OKAY;
    5003
    5004 begin = hmin - 1;
    5005
    5006 minest = INT_MAX;
    5007 maxlct = INT_MIN;
    5008
    5009 /* compute earliest start and latest completion time of all jobs */
    5010 for( v = 0; v < nvars; ++v )
    5011 {
    5013 end = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
    5014
    5015 minest = MIN(minest, start);
    5016 maxlct = MAX(maxlct, end);
    5017 }
    5018
    5019 /* adjust the effective time horizon */
    5020 hmin = MAX(hmin, minest);
    5021 hmax = MIN(hmax, maxlct);
    5022
    5023 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
    5024 totalenergy = computeTotalEnergy(durations, demands, nvars);
    5025
    5026 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
    5027 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
    5028 return SCIP_OKAY;
    5029
    5030 nlcts = 0;
    5031
    5032 /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
    5033 * define the start of the time interval under investigation
    5034 */
    5035 for( v = 0; v < nvars; ++v )
    5036 {
    5037 int flexenergy;
    5038 int minend;
    5039 int ubenergy;
    5040 int ubcand;
    5041 int est;
    5042 int i;
    5043
    5044 est = ests[v];
    5045
    5046 /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
    5047 * infinity capacity is available; hence we skip that
    5048 */
    5049 if( est < hmin )
    5050 continue;
    5051
    5052 /* if the earliest start time is larger or equal then hmax we have to stop */
    5053 if( est >= hmax )
    5054 break;
    5055
    5056 /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
    5057 * induced by start was just analyzed
    5058 */
    5059 if( est == begin )
    5060 continue;
    5061
    5062 assert(est > begin);
    5063
    5064 SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
    5065
    5066 begin = est;
    5067 coreEnergyAfterStart = coreEnergyAfterEst[v];
    5068
    5069 flexenergy = 0;
    5070 minavailable = maxavailable;
    5071 minend = hmin;
    5072 ubcand = -1;
    5073 ubenergy = 0;
    5074
    5075 /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
    5076 * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
    5077 */
    5078 for( i = nlcts; i < nvars; ++i )
    5079 {
    5080 SCIP_VAR* var;
    5081 SCIP_Longint freeenergy;
    5082 int duration;
    5083 int demand;
    5084 int idx;
    5085 int lct;
    5086 int ect;
    5087
    5088 idx = perm[i];
    5089 assert(idx >= 0);
    5090 assert(idx < nvars);
    5091 assert(!(*cutoff));
    5092
    5093 /* the earliest start time of the job */
    5094 lct = lcts[i];
    5095
    5096 /* if the job has a latest completion time before the the current start, we can skip it and do not need to
    5097 * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
    5098 */
    5099 if( lct <= begin )
    5100 {
    5101 nlcts++;
    5102 continue;
    5103 }
    5104
    5105 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
    5106 * start with current beginning time
    5107 */
    5108 if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
    5109 break;
    5110
    5111 var = vars[idx];
    5112 assert(var != NULL);
    5113
    5114 duration = durations[idx];
    5115 assert(duration > 0);
    5116
    5117 demand = demands[idx];
    5118 assert(demand > 0);
    5119
    5121
    5122 /* the earliest completion time of the flexible part of the job */
    5123 ect = ects[idx];
    5124
    5125 /* in case the latest completion time is equal to minend, the job lies completely within the time window under
    5126 * investigation; hence the overload check will do the the job
    5127 */
    5128 assert(lct >= minend);
    5129 if( minavailable < maxavailable && lct > minend )
    5130 {
    5131 assert(!(*cutoff));
    5132
    5133 /* try to tighten the upper bound */
    5134 SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    5135 var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
    5136 initialized, explanation, cutoff) );
    5137
    5138 if( *cutoff )
    5139 return SCIP_OKAY;
    5140 }
    5141
    5142 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
    5143 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
    5144
    5145 end = lct;
    5146 assert(boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
    5147
    5148 /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
    5149 * free energy
    5150 */
    5151 if( end > hmax )
    5152 break;
    5153
    5154 /* compute the contribution to the flexible energy */
    5155 if( est >= begin )
    5156 {
    5157 /* if the jobs has to finish before the end, all the energy has to be scheduled */
    5158 assert(ect <= end);
    5159 assert(flexenergies[idx] >= 0);
    5160 flexenergy += flexenergies[idx];
    5161 }
    5162 else
    5163 {
    5164 /* the job partly overlaps with the end */
    5165 int candenergy;
    5166 int energy;
    5167
    5168 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
    5169 * w.r.t. latest start time
    5170 *
    5171 * @note we need to be aware of the effective horizon
    5172 */
    5173 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
    5174 assert(ect - begin < duration);
    5175 assert(energy >= 0);
    5176
    5177 /* adjust the flexible energy of the time interval */
    5178 flexenergy += energy;
    5179
    5180 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
    5181 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
    5182 assert(candenergy >= 0);
    5183
    5184 /* check if we found a better candidate */
    5185 if( candenergy > ubenergy )
    5186 {
    5187 ubenergy = candenergy;
    5188 ubcand = idx;
    5189 }
    5190 }
    5191
    5192 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
    5193 assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
    5194
    5195 /* compute the energy which is not used yet */
    5196 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
    5197
    5198 /* check overload */
    5199 if( freeenergy < 0 )
    5200 {
    5201 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
    5202
    5203 /* initialize conflict analysis if conflict analysis is applicable */
    5205 {
    5206 /* analyze infeasibilty */
    5208
    5209 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    5211 conshdlrdata->usebdwidening, explanation) );
    5212
    5213 (*initialized) = TRUE;
    5214 }
    5215
    5216 (*cutoff) = TRUE;
    5217
    5218 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
    5220
    5221 return SCIP_OKAY;
    5222 }
    5223
    5224 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
    5225 if( ubenergy > 0 && freeenergy < ubenergy )
    5226 {
    5227 SCIP_Longint energy;
    5228 int newub;
    5229 int lst;
    5230
    5231 duration = durations[ubcand];
    5232 assert(duration > 0);
    5233
    5234 ect = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
    5235 lst = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
    5236
    5237 /* remove the energy of our job from the ... */
    5238 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
    5239
    5240 newub = begin - duration + (int)(energy / demands[ubcand]);
    5241
    5242 if( newub < ect - duration )
    5243 {
    5244 /* initialize conflict analysis if conflict analysis is applicable */
    5246 {
    5247 SCIP_Real relaxedbd;
    5248 /* analyze infeasibilty */
    5250
    5251 relaxedbd = ect - duration - 1.0;
    5252
    5253 /* added to lower bound (which was undercut be new upper bound) of the variable */
    5254 SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
    5255
    5256 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    5257 begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
    5258 conshdlrdata->usebdwidening, explanation) );
    5259
    5260 (*initialized) = TRUE;
    5261 }
    5262
    5263 (*cutoff) = TRUE;
    5264 return SCIP_OKAY;
    5265 }
    5266 else if( newub < newubs[ubcand] )
    5267 {
    5268 INFERINFO inferinfo;
    5269
    5270 /* construct inference information */
    5271 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
    5272
    5273 /* buffer upper bound change */
    5274 ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
    5275 newubs[ubcand] = newub;
    5276 }
    5277 }
    5278
    5279 /* check if the current interval has a smaller free energy */
    5280 if( minavailable > freeenergy )
    5281 {
    5282 minavailable = freeenergy;
    5283 minend = end;
    5284 }
    5285 assert(minavailable >= 0);
    5286 }
    5287 }
    5288
    5289 return SCIP_OKAY;
    5290}
    5291
    5292/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
    5293 * edge-finding
    5294 *
    5295 * @note The algorithm is based on the following two papers:
    5296 * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
    5297 * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
    5298 * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
    5299 * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
    5300 * Cumulative Resource Constraint (submitted to CPAIOR 2013)
    5301 */
    5302static
    5304 SCIP* scip, /**< SCIP data structure */
    5305 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    5306 SCIP_PROFILE* profile, /**< current core profile */
    5307 int nvars, /**< number of start time variables (activities) */
    5308 SCIP_VAR** vars, /**< array of start time variables */
    5309 int* durations, /**< array of durations */
    5310 int* demands, /**< array of demands */
    5311 int capacity, /**< cumulative capacity */
    5312 int hmin, /**< left bound of time axis to be considered (including hmin) */
    5313 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    5314 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
    5315 int* nchgbds, /**< pointer to store the number of bound changes */
    5316 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    5317 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    5318 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    5319 )
    5320{
    5321 int* coreEnergyAfterEst;
    5322 int* coreEnergyAfterLct;
    5323 int* flexenergies;
    5324 int* permests;
    5325 int* permlcts;
    5326 int* lcts;
    5327 int* ests;
    5328 int* ects;
    5329 int* lsts;
    5330
    5331 int* newlbs;
    5332 int* newubs;
    5333 int* lbinferinfos;
    5334 int* ubinferinfos;
    5335
    5336 int v;
    5337
    5338 /* check if a cutoff was already detected */
    5339 if( (*cutoff) )
    5340 return SCIP_OKAY;
    5341
    5342 /* check if at least the basic overload checking should be perfomed */
    5343 if( !conshdlrdata->ttefcheck )
    5344 return SCIP_OKAY;
    5345
    5346 SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
    5347
    5348 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
    5349 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
    5350 SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
    5351 SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
    5352 SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
    5353 SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
    5354 SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
    5355 SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
    5356 SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
    5357
    5358 SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
    5359 SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
    5360 SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
    5361 SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
    5362
    5363 /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
    5364 for( v = 0; v < nvars; ++v )
    5365 {
    5366 newlbs[v] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
    5367 newubs[v] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
    5368 lbinferinfos[v] = 0;
    5369 ubinferinfos[v] = 0;
    5370 }
    5371
    5372 /* collect earliest start times, latest completion time, and free energy contributions */
    5373 collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
    5374
    5375 /* sort the earliest start times and latest completion in non-decreasing order */
    5376 SCIPsortIntInt(ests, permests, nvars);
    5377 SCIPsortIntInt(lcts, permlcts, nvars);
    5378
    5379 /* compute for the different earliest start and latest completion time the core energy of the corresponding time
    5380 * points
    5381 */
    5382 computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
    5383
    5384 /* propagate the upper bounds and "opportunistically" the lower bounds */
    5385 SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    5386 newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
    5387 permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
    5388
    5389 /* propagate the lower bounds and "opportunistically" the upper bounds */
    5390 SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    5391 newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
    5392 permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
    5393
    5394 /* apply the buffer bound changes */
    5395 for( v = 0; v < nvars && !(*cutoff); ++v )
    5396 {
    5397 SCIP_Bool infeasible;
    5398 SCIP_Bool tightened;
    5399
    5400 if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
    5401 {
    5402 SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
    5403 TRUE, &infeasible, &tightened) );
    5404 }
    5405 else
    5406 {
    5407 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
    5408 }
    5409
    5410 /* since we change first the lower bound of the variable an infeasibilty should not be detected */
    5411 assert(!infeasible);
    5412
    5413 if( tightened )
    5414 {
    5415 (*nchgbds)++;
    5416
    5417 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    5419 }
    5420
    5421 if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
    5422 {
    5423 SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
    5424 TRUE, &infeasible, &tightened) );
    5425 }
    5426 else
    5427 {
    5428 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
    5429 }
    5430
    5431 /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
    5432 * bound update can be infeasible
    5433 */
    5434 if( infeasible )
    5435 {
    5436 /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
    5437 * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
    5438 * be analyzed in the case when begin and end exceed the 15 bit limit
    5439 */
    5441 {
    5442 INFERINFO inferinfo;
    5443 SCIP_VAR* var;
    5444 int begin;
    5445 int end;
    5446
    5447 var = vars[v];
    5448 assert(var != NULL);
    5449
    5450 /* initialize conflict analysis */
    5452
    5453 /* convert int to inference information */
    5454 inferinfo = intToInferInfo(ubinferinfos[v]);
    5455
    5456 /* collect time window from inference information */
    5457 begin = inferInfoGetData1(inferinfo);
    5458 end = inferInfoGetData2(inferinfo);
    5459 assert(begin < end);
    5460
    5461 /* added to lower bound (which was undercut be new upper bound) of the variable */
    5463
    5464 /* analysis the upper bound change */
    5465 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    5466 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
    5467 conshdlrdata->usebdwidening, explanation) );
    5468
    5469 (*initialized) = TRUE;
    5470 }
    5471
    5472 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    5474
    5475 (*cutoff) = TRUE;
    5476 break;
    5477 }
    5478
    5479 if( tightened )
    5480 {
    5481 (*nchgbds)++;
    5482
    5483 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    5485 }
    5486 }
    5487
    5488 SCIPfreeBufferArray(scip, &ubinferinfos);
    5489 SCIPfreeBufferArray(scip, &lbinferinfos);
    5490 SCIPfreeBufferArray(scip, &newubs);
    5491 SCIPfreeBufferArray(scip, &newlbs);
    5492
    5493 /* free buffer arrays */
    5494 SCIPfreeBufferArray(scip, &lsts);
    5495 SCIPfreeBufferArray(scip, &ects);
    5496 SCIPfreeBufferArray(scip, &ests);
    5497 SCIPfreeBufferArray(scip, &lcts);
    5498 SCIPfreeBufferArray(scip, &permests);
    5499 SCIPfreeBufferArray(scip, &permlcts);
    5500 SCIPfreeBufferArray(scip, &flexenergies);
    5501 SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
    5502 SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
    5503
    5504 return SCIP_OKAY;
    5505}
    5506
    5507/** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
    5508 * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
    5509 * time table propagator
    5510 */
    5511static
    5513 SCIP* scip, /**< SCIP data structure */
    5514 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    5515 SCIP_PROFILE* profile, /**< core profile */
    5516 int nvars, /**< number of start time variables (activities) */
    5517 SCIP_VAR** vars, /**< array of start time variables */
    5518 int* durations, /**< array of durations */
    5519 int* demands, /**< array of demands */
    5520 int capacity, /**< cumulative capacity */
    5521 int hmin, /**< left bound of time axis to be considered (including hmin) */
    5522 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    5523 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
    5524 int* nchgbds, /**< pointer to store the number of bound changes */
    5525 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    5526 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    5527 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    5528 )
    5529{
    5530 SCIP_Bool infeasible;
    5531 int v;
    5532
    5533 assert(scip != NULL);
    5534 assert(nvars > 0);
    5535 assert(cons != NULL);
    5536 assert(cutoff != NULL);
    5537
    5538 /* check if already a cutoff was detected */
    5539 if( (*cutoff) )
    5540 return SCIP_OKAY;
    5541
    5542 /* check if the time tabling should infer bounds */
    5543 if( !conshdlrdata->ttinfer )
    5544 return SCIP_OKAY;
    5545
    5546 assert(*initialized == FALSE);
    5547
    5548 SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
    5549 SCIPconsGetName(cons), hmin, hmax, capacity);
    5550
    5551 infeasible = FALSE;
    5552
    5553 /* if core profile is empty; nothing to do */
    5554 if( SCIPprofileGetNTimepoints(profile) <= 1 )
    5555 return SCIP_OKAY;
    5556
    5557 /* start checking each job whether the bounds can be improved */
    5558 for( v = 0; v < nvars; ++v )
    5559 {
    5560 SCIP_VAR* var;
    5561 int demand;
    5562 int duration;
    5563 int begin;
    5564 int end;
    5565 int est;
    5566 int lst;
    5567
    5568 var = vars[v];
    5569 assert(var != NULL);
    5570
    5571 duration = durations[v];
    5572 assert(duration > 0);
    5573
    5574 /* collect earliest and latest start time */
    5577
    5578 /* check if the start time variables is already fixed; in that case we can ignore the job */
    5579 if( est == lst )
    5580 continue;
    5581
    5582 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
    5583 if( lst + duration <= hmin || est >= hmax )
    5584 continue;
    5585
    5586 /* compute core interval w.r.t. effective time horizon */
    5587 begin = MAX(hmin, lst);
    5588 end = MIN(hmax, est + duration);
    5589
    5590 demand = demands[v];
    5591 assert(demand > 0);
    5592
    5593 /* if the job has a core, remove it first */
    5594 if( begin < end )
    5595 {
    5596 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
    5597 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
    5598
    5599 SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
    5600 }
    5601
    5602 /* first try to update the earliest start time */
    5603 SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
    5604 profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
    5605
    5606 if( *cutoff )
    5607 break;
    5608
    5609 /* second try to update the latest start time */
    5610 SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
    5611 profile, v, nchgbds) );
    5612
    5613 if( *cutoff )
    5614 break;
    5615
    5616 /* collect the potentially updated earliest and latest start time */
    5619
    5620 /* compute core interval w.r.t. effective time horizon */
    5621 begin = MAX(hmin, lst);
    5622 end = MIN(hmax, est + duration);
    5623
    5624 /* after updating the bound we might have a new core */
    5625 if( begin < end )
    5626 {
    5627 int pos;
    5628
    5629 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
    5630 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
    5631
    5632 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
    5633
    5634 if( infeasible )
    5635 {
    5636 /* use conflict analysis to analysis the core insertion which was infeasible */
    5637 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    5638 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
    5639
    5640 if( explanation != NULL )
    5641 explanation[v] = TRUE;
    5642
    5643 (*cutoff) = TRUE;
    5644
    5645 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    5647
    5648 break;
    5649 }
    5650 }
    5651 }
    5652
    5653 return SCIP_OKAY;
    5654}
    5655
    5656
    5657/** node data structure for the binary tree used for edgefinding (with overload checking) */
    5658struct SCIP_NodeData
    5659{
    5660 SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
    5661 SCIP_Real key; /**< key which is to insert the corresponding search node */
    5662 int est; /**< earliest start time if the node data belongs to a leaf */
    5663 int lct; /**< latest completion time if the node data belongs to a leaf */
    5664 int demand; /**< demand of the job if the node data belongs to a leaf */
    5665 int duration; /**< duration of the job if the node data belongs to a leaf */
    5666 int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
    5667 int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
    5668 SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
    5669 int energytheta; /**< energy of the subset of the jobs which are part of theta set */
    5670 int energylambda;
    5671 SCIP_Longint enveloplambda;
    5672 int idx; /**< index of the start time variable in the (global) variable array */
    5673 SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
    5674};
    5675typedef struct SCIP_NodeData SCIP_NODEDATA;
    5676
    5677
    5678/** update node data structure starting from the given node along the path to the root node */
    5679static
    5681 SCIP* scip, /**< SCIP data structure */
    5682 SCIP_BTNODE* node /**< search node which inserted */
    5683 )
    5684{
    5685 SCIP_BTNODE* left;
    5686 SCIP_BTNODE* right;
    5688 SCIP_NODEDATA* leftdata;
    5689 SCIP_NODEDATA* rightdata;
    5690
    5691 SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
    5692
    5693 if( SCIPbtnodeIsLeaf(node) )
    5694 node = SCIPbtnodeGetParent(node);
    5695
    5696 while( node != NULL )
    5697 {
    5698 /* get node data */
    5700 assert(nodedata != NULL);
    5701
    5702 /* collect node data from left node */
    5703 left = SCIPbtnodeGetLeftchild(node);
    5704 assert(left != NULL);
    5705 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    5706 assert(leftdata != NULL);
    5707
    5708 /* collect node data from right node */
    5709 right = SCIPbtnodeGetRightchild(node);
    5710 assert(right != NULL);
    5711 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    5712 assert(rightdata != NULL);
    5713
    5714 /* update envelop and energy */
    5715 if( leftdata->enveloptheta >= 0 )
    5716 {
    5717 assert(rightdata->energytheta != -1);
    5718 nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
    5719 }
    5720 else
    5721 nodedata->enveloptheta = rightdata->enveloptheta;
    5722
    5723 assert(leftdata->energytheta != -1);
    5724 assert(rightdata->energytheta != -1);
    5725 nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
    5726
    5727 if( leftdata->enveloplambda >= 0 )
    5728 {
    5729 assert(rightdata->energytheta != -1);
    5730 nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
    5731 }
    5732 else
    5733 nodedata->enveloplambda = rightdata->enveloplambda;
    5734
    5735 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
    5736 nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
    5737
    5738 SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
    5739
    5740 if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
    5741 {
    5742 assert(rightdata->energytheta != -1);
    5743 assert(leftdata->energytheta != -1);
    5744 nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
    5745 }
    5746 else if( rightdata->energylambda >= 0 )
    5747 {
    5748 assert(leftdata->energytheta != -1);
    5749 nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
    5750 }
    5751 else if( leftdata->energylambda >= 0 )
    5752 {
    5753 assert(rightdata->energytheta != -1);
    5754 nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
    5755 }
    5756 else
    5757 nodedata->energylambda = -1;
    5758
    5759 /* go to parent */
    5760 node = SCIPbtnodeGetParent(node);
    5761 }
    5762
    5763 SCIPdebugMsg(scip, "updating done\n");
    5764}
    5765
    5766/** updates the key of the first parent on the trace which comes from left */
    5767static
    5769 SCIP_BTNODE* node, /**< node to start the trace */
    5770 SCIP_Real key /**< update search key */
    5771 )
    5772{
    5773 assert(node != NULL);
    5774
    5775 while( !SCIPbtnodeIsRoot(node) )
    5776 {
    5777 SCIP_BTNODE* parent;
    5778
    5779 parent = SCIPbtnodeGetParent(node);
    5780 assert(parent != NULL);
    5781
    5782 if( SCIPbtnodeIsLeftchild(node) )
    5783 {
    5785
    5787 assert(nodedata != NULL);
    5788
    5789 nodedata->key = key;
    5790 return;
    5791 }
    5792
    5793 node = parent;
    5794 }
    5795}
    5796
    5797
    5798/** deletes the given node and updates all envelops */
    5799static
    5801 SCIP* scip, /**< SCIP data structure */
    5802 SCIP_BT* tree, /**< binary tree */
    5803 SCIP_BTNODE* node /**< node to be deleted */
    5804 )
    5805{
    5806 SCIP_BTNODE* parent;
    5807 SCIP_BTNODE* grandparent;
    5808 SCIP_BTNODE* sibling;
    5809
    5810 assert(scip != NULL);
    5811 assert(tree != NULL);
    5812 assert(node != NULL);
    5813
    5814 assert(SCIPbtnodeIsLeaf(node));
    5815 assert(!SCIPbtnodeIsRoot(node));
    5816
    5817 SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
    5818
    5819 parent = SCIPbtnodeGetParent(node);
    5820 assert(parent != NULL);
    5821 if( SCIPbtnodeIsLeftchild(node) )
    5822 {
    5823 sibling = SCIPbtnodeGetRightchild(parent);
    5825 }
    5826 else
    5827 {
    5828 sibling = SCIPbtnodeGetLeftchild(parent);
    5830 }
    5831 assert(sibling != NULL);
    5832
    5833 grandparent = SCIPbtnodeGetParent(parent);
    5834
    5835 if( grandparent != NULL )
    5836 {
    5837 /* reset parent of sibling */
    5838 SCIPbtnodeSetParent(sibling, grandparent);
    5839
    5840 /* reset child of grandparent to sibling */
    5841 if( SCIPbtnodeIsLeftchild(parent) )
    5842 {
    5843 SCIPbtnodeSetLeftchild(grandparent, sibling);
    5844 }
    5845 else
    5846 {
    5848
    5849 assert(SCIPbtnodeIsRightchild(parent));
    5850 SCIPbtnodeSetRightchild(grandparent, sibling);
    5851
    5853
    5854 updateKeyOnTrace(grandparent, nodedata->key);
    5855 }
    5856
    5857 updateEnvelope(scip, grandparent);
    5858 }
    5859 else
    5860 {
    5861 SCIPbtnodeSetParent(sibling, NULL);
    5862
    5863 SCIPbtSetRoot(tree, sibling);
    5864 }
    5865
    5866 SCIPbtnodeFree(tree, &parent);
    5867
    5868 return SCIP_OKAY;
    5869}
    5870
    5871/** moves a node form the theta set into the lambda set and updates the envelops */
    5872static
    5874 SCIP* scip, /**< SCIP data structure */
    5875 SCIP_BT* tree, /**< binary tree */
    5876 SCIP_BTNODE* node /**< node to move into the lambda set */
    5877 )
    5878{
    5880
    5881 assert(scip != NULL);
    5882 assert(tree != NULL);
    5883 assert(node != NULL);
    5884
    5886 assert(nodedata != NULL);
    5887 assert(nodedata->intheta);
    5888
    5889 /* move the contributions form the theta set into the lambda set */
    5890 assert(nodedata->enveloptheta != -1);
    5891 assert(nodedata->energytheta != -1);
    5892 assert(nodedata->enveloplambda == -1);
    5893 assert(nodedata->energylambda == -1);
    5894 nodedata->enveloplambda = nodedata->enveloptheta;
    5895 nodedata->energylambda = nodedata->energytheta;
    5896
    5897 nodedata->enveloptheta = -1;
    5898 nodedata->energytheta = 0;
    5899 nodedata->intheta = FALSE;
    5900
    5901 /* update the energy and envelop values on trace */
    5902 updateEnvelope(scip, node);
    5903
    5904 return SCIP_OKAY;
    5905}
    5906
    5907/** inserts a node into the theta set and update the envelops */
    5908static
    5910 SCIP* scip, /**< SCIP data structure */
    5911 SCIP_BT* tree, /**< binary tree */
    5912 SCIP_BTNODE* node, /**< node to insert */
    5913 SCIP_NODEDATA* nodedatas, /**< array of node data */
    5914 int* nodedataidx, /**< array of indices for node data */
    5915 int* nnodedatas /**< pointer to number of node data */
    5916 )
    5917{
    5918 /* if the tree is empty the node will be the root node */
    5919 if( SCIPbtIsEmpty(tree) )
    5920 {
    5921 SCIPbtSetRoot(tree, node);
    5922 }
    5923 else
    5924 {
    5925 SCIP_NODEDATA* newnodedata;
    5926 SCIP_NODEDATA* leafdata;
    5928 SCIP_BTNODE* leaf;
    5929 SCIP_BTNODE* newnode;
    5930 SCIP_BTNODE* parent;
    5931
    5932 leaf = SCIPbtGetRoot(tree);
    5933 assert(leaf != NULL);
    5934
    5935 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
    5936 assert(leafdata != NULL);
    5937
    5939 assert(nodedata != NULL);
    5940 assert(nodedata->intheta);
    5941
    5942 /* find the position to insert the node */
    5943 while( !SCIPbtnodeIsLeaf(leaf) )
    5944 {
    5945 if( nodedata->key < leafdata->key )
    5946 leaf = SCIPbtnodeGetLeftchild(leaf);
    5947 else
    5948 leaf = SCIPbtnodeGetRightchild(leaf);
    5949
    5950 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
    5951 assert(leafdata != NULL);
    5952 }
    5953
    5954 assert(leaf != NULL);
    5955 assert(leaf != node);
    5956
    5957 /* store node data to be able to delete them latter */
    5958 newnodedata = &nodedatas[*nnodedatas];
    5959 nodedataidx[*nnodedatas] = *nnodedatas;
    5960 ++(*nnodedatas);
    5961
    5962 /* init node data */
    5963 newnodedata->var = NULL;
    5964 newnodedata->key = SCIP_INVALID;
    5965 newnodedata->est = INT_MIN;
    5966 newnodedata->lct = INT_MAX;
    5967 newnodedata->duration = 0;
    5968 newnodedata->demand = 0;
    5969 newnodedata->enveloptheta = -1;
    5970 newnodedata->energytheta = 0;
    5971 newnodedata->enveloplambda = -1;
    5972 newnodedata->energylambda = -1;
    5973 newnodedata->idx = -1;
    5974 newnodedata->intheta = TRUE;
    5975
    5976 /* create a new node */
    5977 SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
    5978 assert(newnode != NULL);
    5979
    5980 parent = SCIPbtnodeGetParent(leaf);
    5981
    5982 if( parent != NULL )
    5983 {
    5984 SCIPbtnodeSetParent(newnode, parent);
    5985
    5986 /* check if the node is the left child */
    5987 if( SCIPbtnodeGetLeftchild(parent) == leaf )
    5988 {
    5989 SCIPbtnodeSetLeftchild(parent, newnode);
    5990 }
    5991 else
    5992 {
    5993 SCIPbtnodeSetRightchild(parent, newnode);
    5994 }
    5995 }
    5996 else
    5997 SCIPbtSetRoot(tree, newnode);
    5998
    5999 if( nodedata->key < leafdata->key )
    6000 {
    6001 /* node is on the left */
    6002 SCIPbtnodeSetLeftchild(newnode, node);
    6003 SCIPbtnodeSetRightchild(newnode, leaf);
    6004 newnodedata->key = nodedata->key;
    6005 }
    6006 else
    6007 {
    6008 /* leaf is on the left */
    6009 SCIPbtnodeSetLeftchild(newnode, leaf);
    6010 SCIPbtnodeSetRightchild(newnode, node);
    6011 newnodedata->key = leafdata->key;
    6012 }
    6013
    6014 SCIPbtnodeSetParent(leaf, newnode);
    6015 SCIPbtnodeSetParent(node, newnode);
    6016 }
    6017
    6018 /* update envelop */
    6019 updateEnvelope(scip, node);
    6020
    6021 return SCIP_OKAY;
    6022}
    6023
    6024/** returns the leaf responsible for the lambda energy */
    6025static
    6027 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
    6028 )
    6029{
    6030 SCIP_BTNODE* left;
    6031 SCIP_BTNODE* right;
    6033 SCIP_NODEDATA* leftdata;
    6034 SCIP_NODEDATA* rightdata;
    6035
    6036 assert(node != NULL);
    6037
    6039 assert(nodedata != NULL);
    6040
    6041 /* check if the node is the (responsible) leaf */
    6042 if( SCIPbtnodeIsLeaf(node) )
    6043 {
    6044 assert(!nodedata->intheta);
    6045 return node;
    6046 }
    6047
    6048 left = SCIPbtnodeGetLeftchild(node);
    6049 assert(left != NULL);
    6050
    6051 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6052 assert(leftdata != NULL);
    6053
    6054 right = SCIPbtnodeGetRightchild(node);
    6055 assert(right != NULL);
    6056
    6057 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6058 assert(rightdata != NULL);
    6059
    6060 assert(nodedata->energylambda != -1);
    6061 assert(rightdata->energytheta != -1);
    6062
    6063 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
    6065
    6066 assert(leftdata->energytheta != -1);
    6067 assert(rightdata->energylambda != -1);
    6068 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
    6069
    6071}
    6072
    6073/** returns the leaf responsible for the lambda envelop */
    6074static
    6076 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
    6077 )
    6078{
    6079 SCIP_BTNODE* left;
    6080 SCIP_BTNODE* right;
    6082 SCIP_NODEDATA* leftdata;
    6083 SCIP_NODEDATA* rightdata;
    6084
    6085 assert(node != NULL);
    6086
    6088 assert(nodedata != NULL);
    6089
    6090 /* check if the node is the (responsible) leaf */
    6091 if( SCIPbtnodeIsLeaf(node) )
    6092 {
    6093 assert(!nodedata->intheta);
    6094 return node;
    6095 }
    6096
    6097 left = SCIPbtnodeGetLeftchild(node);
    6098 assert(left != NULL);
    6099
    6100 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6101 assert(leftdata != NULL);
    6102
    6103 right = SCIPbtnodeGetRightchild(node);
    6104 assert(right != NULL);
    6105
    6106 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6107 assert(rightdata != NULL);
    6108
    6109 assert(nodedata->enveloplambda != -1);
    6110 assert(rightdata->energytheta != -1);
    6111
    6112 /* check if the left or right child is the one defining the envelop for the lambda set */
    6113 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
    6115 else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
    6116 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
    6118
    6119 assert(rightdata->enveloplambda != -1);
    6120 assert(nodedata->enveloplambda == rightdata->enveloplambda);
    6121
    6123}
    6124
    6125
    6126/** reports all elements from set theta to generate a conflicting set */
    6127static
    6129 SCIP_BTNODE* node, /**< node within a theta subtree */
    6130 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
    6131 int* nelements, /**< pointer to store the number of elements in omegaset */
    6132 int* est, /**< pointer to store the earliest start time of the omega set */
    6133 int* lct, /**< pointer to store the latest start time of the omega set */
    6134 int* energy /**< pointer to store the energy of the omega set */
    6135 )
    6136{
    6138
    6140 assert(nodedata != NULL);
    6141
    6142 if( !SCIPbtnodeIsLeaf(node) )
    6143 {
    6144 collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
    6145 collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
    6146 }
    6147 else if( nodedata->intheta )
    6148 {
    6149 assert(nodedata->var != NULL);
    6150 SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
    6151
    6152 omegaset[*nelements] = node;
    6153 (*est) = MIN(*est, nodedata->est);
    6154 (*lct) = MAX(*lct, nodedata->lct);
    6155 (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
    6156 (*nelements)++;
    6157 }
    6158}
    6159
    6160
    6161/** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
    6162static
    6164 SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
    6165 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
    6166 int* nelements, /**< pointer to store the number of elements in omegaset */
    6167 int* est, /**< pointer to store the earliest start time of the omega set */
    6168 int* lct, /**< pointer to store the latest start time of the omega set */
    6169 int* energy /**< pointer to store the energy of the omega set */
    6170 )
    6171{
    6172 assert(node != NULL);
    6173
    6174 if( SCIPbtnodeIsLeaf(node) )
    6175 {
    6176 collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
    6177 }
    6178 else
    6179 {
    6180 SCIP_BTNODE* left;
    6181 SCIP_BTNODE* right;
    6183 SCIP_NODEDATA* leftdata;
    6184 SCIP_NODEDATA* rightdata;
    6185
    6187 assert(nodedata != NULL);
    6188
    6189 left = SCIPbtnodeGetLeftchild(node);
    6190 assert(left != NULL);
    6191
    6192 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6193 assert(leftdata != NULL);
    6194
    6195 right = SCIPbtnodeGetRightchild(node);
    6196 assert(right != NULL);
    6197
    6198 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6199 assert(rightdata != NULL);
    6200
    6202 assert(nodedata != NULL);
    6203
    6204 assert(nodedata->enveloptheta != -1);
    6205 assert(rightdata->energytheta != -1);
    6206
    6207 if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
    6208 {
    6209 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
    6210 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
    6211 }
    6212 else
    6213 {
    6214 assert(rightdata->enveloptheta != -1);
    6215 assert(nodedata->enveloptheta == rightdata->enveloptheta);
    6216 traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
    6217 }
    6218 }
    6219}
    6220
    6221/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
    6222static
    6224 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
    6225 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
    6226 int* nelements, /**< pointer to store the number of elements in omega set */
    6227 int* est, /**< pointer to store the earliest start time of the omega set */
    6228 int* lct, /**< pointer to store the latest start time of the omega set */
    6229 int* energy /**< pointer to store the energy of the omega set */
    6230 )
    6231{
    6232 SCIP_BTNODE* left;
    6233 SCIP_BTNODE* right;
    6235 SCIP_NODEDATA* leftdata;
    6236 SCIP_NODEDATA* rightdata;
    6237
    6238 assert(node != NULL);
    6239
    6241 assert(nodedata != NULL);
    6242
    6243 /* check if the node is a leaf */
    6244 if( SCIPbtnodeIsLeaf(node) )
    6245 return;
    6246
    6247 left = SCIPbtnodeGetLeftchild(node);
    6248 assert(left != NULL);
    6249
    6250 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6251 assert(leftdata != NULL);
    6252
    6253 right = SCIPbtnodeGetRightchild(node);
    6254 assert(right != NULL);
    6255
    6256 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6257 assert(rightdata != NULL);
    6258
    6259 assert(nodedata->energylambda != -1);
    6260 assert(rightdata->energytheta != -1);
    6261
    6262 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
    6263 {
    6264 traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
    6265 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
    6266 }
    6267 else
    6268 {
    6269 assert(leftdata->energytheta != -1);
    6270 assert(rightdata->energylambda != -1);
    6271 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
    6272
    6273 collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
    6274 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
    6275 }
    6276}
    6277
    6278/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
    6279static
    6281 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
    6282 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
    6283 int* nelements, /**< pointer to store the number of elements in omega set */
    6284 int* est, /**< pointer to store the earliest start time of the omega set */
    6285 int* lct, /**< pointer to store the latest start time of the omega set */
    6286 int* energy /**< pointer to store the energy of the omega set */
    6287 )
    6288{
    6289 SCIP_BTNODE* left;
    6290 SCIP_BTNODE* right;
    6292 SCIP_NODEDATA* leftdata;
    6293 SCIP_NODEDATA* rightdata;
    6294
    6295 assert(node != NULL);
    6296
    6298 assert(nodedata != NULL);
    6299
    6300 /* check if the node is a leaf */
    6301 if( SCIPbtnodeIsLeaf(node) )
    6302 {
    6303 assert(!nodedata->intheta);
    6304 return;
    6305 }
    6306
    6307 left = SCIPbtnodeGetLeftchild(node);
    6308 assert(left != NULL);
    6309
    6310 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6311 assert(leftdata != NULL);
    6312
    6313 right = SCIPbtnodeGetRightchild(node);
    6314 assert(right != NULL);
    6315
    6316 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6317 assert(rightdata != NULL);
    6318
    6319 assert(nodedata->enveloplambda != -1);
    6320 assert(rightdata->energytheta != -1);
    6321
    6322 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
    6323 {
    6324 traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
    6325 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
    6326 }
    6327 else
    6328 {
    6329 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
    6330 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
    6331 {
    6332 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
    6333 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
    6334 }
    6335 else
    6336 {
    6337 assert(rightdata->enveloplambda != -1);
    6338 assert(nodedata->enveloplambda == rightdata->enveloplambda);
    6339 traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
    6340 }
    6341 }
    6342}
    6343
    6344/** compute the energy contribution by job which corresponds to the given leaf */
    6345static
    6347 SCIP_BTNODE* node /**< leaf */
    6348 )
    6349{
    6351 int duration;
    6352
    6354 assert(nodedata != NULL);
    6355 assert(nodedata->var != NULL);
    6356
    6357 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
    6358 assert(duration > 0);
    6359
    6360 SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
    6362 SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
    6363
    6364 /* return energy which is contributed by the start time variable */
    6365 return nodedata->demand * duration;
    6366}
    6367
    6368/** comparison method for two node data w.r.t. the earliest start time */
    6369static
    6371{
    6372 int est1;
    6373 int est2;
    6374
    6375 est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
    6376 est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
    6377
    6378 return (est1 - est2);
    6379}
    6380
    6381/** comparison method for two node data w.r.t. the latest completion time */
    6382static
    6384{
    6385 SCIP_NODEDATA* nodedatas;
    6386
    6387 nodedatas = (SCIP_NODEDATA*) dataptr;
    6388 return (nodedatas[ind1].lct - nodedatas[ind2].lct);
    6389}
    6390
    6391
    6392/** an overload was detected; initialized conflict analysis, add an initial reason
    6393 *
    6394 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
    6395 */
    6396static
    6398 SCIP* scip, /**< SCIP data structure */
    6399 SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
    6400 int capacity, /**< cumulative capacity */
    6401 int nleaves, /**< number of responsible leaves */
    6402 int est, /**< earliest start time of the ...... */
    6403 int lct, /**< latest completly time of the .... */
    6404 int reportedenergy, /**< energy which already reported */
    6405 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
    6406 int shift, /**< shift applied to all jobs before adding them to the tree */
    6407 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    6408 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    6409 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    6410 )
    6411{
    6412 SCIP_Longint energy;
    6413 int j;
    6414
    6415 /* do nothing if conflict analysis is not applicable */
    6417 return SCIP_OKAY;
    6418
    6419 SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
    6420
    6421 /* compute energy of initial time window */
    6422 energy = ((SCIP_Longint) lct - est) * capacity;
    6423
    6424 /* sort the start time variables which were added to search tree w.r.t. earliest start time */
    6425 SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
    6426
    6427 /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
    6428 * thereby, compute the time window of interest
    6429 */
    6430 for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
    6431 {
    6433
    6435 assert(nodedata != NULL);
    6436
    6437 reportedenergy += computeEnergyContribution(leaves[j]);
    6438
    6439 /* adjust energy if the earliest start time decrease */
    6440 if( nodedata->est < est )
    6441 {
    6442 est = nodedata->est;
    6443 energy = ((SCIP_Longint) lct - est) * capacity;
    6444 }
    6445 }
    6446 assert(reportedenergy > energy);
    6447
    6448 SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
    6449
    6450 /* initialize conflict analysis */
    6452
    6453 /* flip earliest start time and latest completion time */
    6454 if( !propest )
    6455 {
    6456 SCIPswapInts(&est, &lct);
    6457
    6458 /* shift earliest start time and latest completion time */
    6459 lct = shift - lct;
    6460 est = shift - est;
    6461 }
    6462 else
    6463 {
    6464 /* shift earliest start time and latest completion time */
    6465 lct = lct + shift;
    6466 est = est + shift;
    6467 }
    6468
    6469 nleaves = j;
    6470
    6471 /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
    6472 * overloaded
    6473 */
    6474 for( j = nleaves-1; j >= 0; --j )
    6475 {
    6477
    6479 assert(nodedata != NULL);
    6480 assert(nodedata->var != NULL);
    6481
    6482 /* check if bound widening should be used */
    6483 if( usebdwidening )
    6484 {
    6485 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
    6486 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
    6487 }
    6488 else
    6489 {
    6492 }
    6493
    6494 if( explanation != NULL )
    6495 explanation[nodedata->idx] = TRUE;
    6496 }
    6497
    6498 (*initialized) = TRUE;
    6499
    6500 return SCIP_OKAY;
    6501}
    6502
    6503/** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
    6504 * responsible interval bounds in *est_omega and *lct_omega
    6505 */
    6506static
    6508 SCIP* scip, /**< SCIP data structure */
    6509 int duration, /**< duration of the job to move */
    6510 int demand, /**< demand of the job to move */
    6511 int capacity, /**< cumulative capacity */
    6512 int est, /**< earliest start time of the omega set */
    6513 int lct, /**< latest start time of the omega set */
    6514 int energy /**< energy of the omega set */
    6515 )
    6516{
    6517 int newest;
    6518
    6519 newest = 0;
    6520
    6521 assert(scip != NULL);
    6522
    6523 if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
    6524 {
    6525 if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
    6526 {
    6527 newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
    6528 newest += est;
    6529 }
    6530 }
    6531
    6532 return newest;
    6533}
    6534
    6535/** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
    6536 *
    6537 * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
    6538 * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
    6539 */
    6540static
    6542 SCIP* scip, /**< SCIP data structure */
    6543 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    6544 SCIP_CONS* cons, /**< constraint which is propagated */
    6545 SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
    6546 SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
    6547 int capacity, /**< cumulative capacity */
    6548 int ncands, /**< number of candidates */
    6549 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
    6550 int shift, /**< shift applied to all jobs before adding them to the tree */
    6551 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    6552 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    6553 int* nchgbds, /**< pointer to store the number of bound changes */
    6554 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    6555 )
    6556{
    6557 SCIP_NODEDATA* rootdata;
    6558 int j;
    6559
    6560 assert(!SCIPbtIsEmpty(tree));
    6561
    6562 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
    6563 assert(rootdata != NULL);
    6564
    6565 /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
    6566 for( j = ncands-1; j >= 0 && !(*cutoff); --j )
    6567 {
    6569
    6570 if( SCIPbtnodeIsRoot(leaves[j]) )
    6571 break;
    6572
    6574 assert(nodedata->est != -1);
    6575
    6576 /* check if the root lambda envelop exeeds the available capacity */
    6577 while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
    6578 {
    6579 SCIP_BTNODE** omegaset;
    6580 SCIP_BTNODE* leaf;
    6581 SCIP_NODEDATA* leafdata;
    6582 int nelements;
    6583 int energy;
    6584 int newest;
    6585 int est;
    6586 int lct;
    6587
    6588 assert(!(*cutoff));
    6589
    6590 /* find responsible leaf for the lambda envelope */
    6592 assert(leaf != NULL);
    6593 assert(SCIPbtnodeIsLeaf(leaf));
    6594
    6595 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
    6596 assert(leafdata != NULL);
    6597 assert(!leafdata->intheta);
    6598 assert(leafdata->duration > 0);
    6599 assert(leafdata->est >= 0);
    6600
    6601 /* check if the job has to be removed since its latest completion is to large */
    6602 if( leafdata->est + leafdata->duration >= nodedata->lct )
    6603 {
    6604 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
    6605
    6606 /* the root might changed therefore we need to collect the new root node data */
    6607 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
    6608 assert(rootdata != NULL);
    6609
    6610 continue;
    6611 }
    6612
    6613 /* compute omega set */
    6614 SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
    6615
    6616 nelements = 0;
    6617 est = INT_MAX;
    6618 lct = INT_MIN;
    6619 energy = 0;
    6620
    6621 /* collect the omega set from theta set */
    6622 traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
    6623 assert(nelements > 0);
    6624 assert(nelements < ncands);
    6625
    6626 newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
    6627
    6628 /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
    6629 if( newest > lct )
    6630 {
    6631 SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
    6632
    6633 /* analyze over load */
    6634 SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
    6635 conshdlrdata->usebdwidening, initialized, explanation) );
    6636 (*cutoff) = TRUE;
    6637
    6638 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
    6640 }
    6641 else if( newest > 0 )
    6642 {
    6643 SCIP_Bool infeasible;
    6644 SCIP_Bool tightened;
    6645 INFERINFO inferinfo;
    6646
    6647 if( propest )
    6648 {
    6649 /* constuct inference information; store used propagation rule and the the time window of the omega set */
    6650 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
    6651
    6652 SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
    6653 SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
    6654
    6655 if( inferInfoIsValid(inferinfo) )
    6656 {
    6657 SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
    6658 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
    6659 }
    6660 else
    6661 {
    6662 SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
    6663 TRUE, &infeasible, &tightened) );
    6664 }
    6665
    6666 /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
    6668 }
    6669 else
    6670 {
    6671 /* constuct inference information; store used propagation rule and the the time window of the omega set */
    6672 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
    6673
    6674 SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
    6675 SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
    6676
    6677 if( inferInfoIsValid(inferinfo) )
    6678 {
    6679 SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
    6680 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
    6681 }
    6682 else
    6683 {
    6684 SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
    6685 TRUE, &infeasible, &tightened) );
    6686 }
    6687
    6688 /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
    6690 }
    6691
    6692 /* adjust the earliest start time */
    6693 if( tightened )
    6694 {
    6695 leafdata->est = newest;
    6696 (*nchgbds)++;
    6697 }
    6698
    6699 if( infeasible )
    6700 {
    6701 /* initialize conflict analysis if conflict analysis is applicable */
    6703 {
    6704 int i;
    6705
    6706 SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
    6707
    6709
    6710 /* add lower and upper bound of variable which leads to the infeasibilty */
    6711 SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
    6712 SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
    6713
    6714 if( explanation != NULL )
    6715 explanation[leafdata->idx] = TRUE;
    6716
    6717 /* add lower and upper bound of variable which lead to the infeasibilty */
    6718 for( i = 0; i < nelements; ++i )
    6719 {
    6720 nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
    6721 assert(nodedata != NULL);
    6722
    6725
    6726 if( explanation != NULL )
    6727 explanation[nodedata->idx] = TRUE;
    6728 }
    6729
    6730 (*initialized) = TRUE;
    6731 }
    6732
    6733 (*cutoff) = TRUE;
    6734
    6735 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
    6737 }
    6738 }
    6739
    6740 /* free omegaset array */
    6741 SCIPfreeBufferArray(scip, &omegaset);
    6742
    6743 /* delete responsible leaf from lambda */
    6744 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
    6745
    6746 /* the root might changed therefore we need to collect the new root node data */
    6747 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
    6748 assert(rootdata != NULL);
    6749 }
    6750
    6751 /* move current job j from the theta set into the lambda set */
    6752 SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
    6753 }
    6754
    6755 return SCIP_OKAY;
    6756}
    6757
    6758/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
    6759 *
    6760 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
    6761 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
    6762 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
    6763 */
    6764static
    6766 SCIP* scip, /**< SCIP data structure */
    6767 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    6768 int nvars, /**< number of start time variables (activities) */
    6769 SCIP_VAR** vars, /**< array of start time variables */
    6770 int* durations, /**< array of durations */
    6771 int* demands, /**< array of demands */
    6772 int capacity, /**< cumulative capacity */
    6773 int hmin, /**< left bound of time axis to be considered (including hmin) */
    6774 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    6775 SCIP_CONS* cons, /**< constraint which is propagated */
    6776 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
    6777 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    6778 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    6779 int* nchgbds, /**< pointer to store the number of bound changes */
    6780 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    6781 )
    6782{
    6783 SCIP_NODEDATA* nodedatas;
    6784 SCIP_BTNODE** leaves;
    6785 SCIP_BT* tree;
    6786 int* nodedataidx;
    6787
    6788 int totalenergy;
    6789 int nnodedatas;
    6790 int ninsertcands;
    6791 int ncands;
    6792
    6793 int shift;
    6794 int idx = -1;
    6795 int j;
    6796
    6797 assert(scip != NULL);
    6798 assert(cons != NULL);
    6799 assert(initialized != NULL);
    6800 assert(cutoff != NULL);
    6801 assert(*cutoff == FALSE);
    6802
    6803 SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
    6804
    6805 SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
    6806 SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
    6807 SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
    6808
    6809 ncands = 0;
    6810 totalenergy = 0;
    6811
    6813
    6814 /* compute the shift which we apply to compute .... latest completion time of all jobs */
    6815 if( propest )
    6816 shift = 0;
    6817 else
    6818 {
    6819 shift = 0;
    6820
    6821 /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
    6822 * earliest start time propagation to handle the latest completion times
    6823 */
    6824 for( j = 0; j < nvars; ++j )
    6825 {
    6826 int lct;
    6827
    6828 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
    6829 shift = MAX(shift, lct);
    6830 }
    6831 }
    6832
    6833 /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
    6834 * horizon
    6835 */
    6836 for( j = 0; j < nvars; ++j )
    6837 {
    6839 SCIP_VAR* var;
    6840 int duration;
    6841 int leftadjust;
    6842 int rightadjust;
    6843 int energy;
    6844 int est;
    6845 int lct;
    6846
    6847 var = vars[j];
    6848 assert(var != NULL);
    6849
    6850 duration = durations[j];
    6851 assert(duration > 0);
    6852
    6853 leftadjust = 0;
    6854 rightadjust = 0;
    6855
    6857 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
    6858
    6859 /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
    6860 * effective horizon [hmin,hmax)
    6861 */
    6862 if( conshdlrdata->useadjustedjobs )
    6863 {
    6864 if( est < hmin )
    6865 {
    6866 leftadjust = (hmin - est);
    6867 est = hmin;
    6868 }
    6869 if( lct > hmax )
    6870 {
    6871 rightadjust = (lct - hmax);
    6872 lct = hmax;
    6873 }
    6874
    6875 /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
    6876 * with the effective time horizon
    6877 */
    6878 if( duration - leftadjust - rightadjust <= 0 )
    6879 continue;
    6880 }
    6881 else if( est < hmin || lct > hmax )
    6882 continue;
    6883
    6884 energy = demands[j] * (duration - leftadjust - rightadjust);
    6885 assert(energy > 0);
    6886
    6887 totalenergy += energy;
    6888
    6889 /* flip earliest start time and latest completion time */
    6890 if( !propest )
    6891 {
    6892 SCIPswapInts(&est, &lct);
    6893
    6894 /* shift earliest start time and latest completion time */
    6895 lct = shift - lct;
    6896 est = shift - est;
    6897 }
    6898 else
    6899 {
    6900 /* shift earliest start time and latest completion time */
    6901 lct = lct - shift;
    6902 est = est - shift;
    6903 }
    6904 assert(est < lct);
    6905 assert(est >= 0);
    6906 assert(lct >= 0);
    6907
    6908 /* create search node data */
    6909 nodedata = &nodedatas[ncands];
    6910 nodedataidx[ncands] = ncands;
    6911 ++ncands;
    6912
    6913 /* initialize search node data */
    6914 /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
    6915 nodedata->key = est + j / (2.0 * nvars);
    6916 nodedata->var = var;
    6917 nodedata->est = est;
    6918 nodedata->lct = lct;
    6919 nodedata->demand = demands[j];
    6920 nodedata->duration = duration;
    6921 nodedata->leftadjust = leftadjust;
    6922 nodedata->rightadjust = rightadjust;
    6923
    6924 /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
    6925 * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
    6926 * particular time interval [a,b] against the time interval [0,b].
    6927 */
    6928 nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
    6929 nodedata->energytheta = energy;
    6930 nodedata->enveloplambda = -1;
    6931 nodedata->energylambda = -1;
    6932
    6933 nodedata->idx = j;
    6934 nodedata->intheta = TRUE;
    6935 }
    6936
    6937 nnodedatas = ncands;
    6938
    6939 /* sort (non-decreasing) the jobs w.r.t. latest completion times */
    6940 SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
    6941
    6942 ninsertcands = 0;
    6943
    6944 /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
    6945 * the root envelop detects an overload
    6946 */
    6947 for( j = 0; j < ncands; ++j )
    6948 {
    6949 SCIP_BTNODE* leaf;
    6950 SCIP_NODEDATA* rootdata;
    6951
    6952 idx = nodedataidx[j];
    6953
    6954 /* check if the new job opens a time window which size is so large that it offers more energy than the total
    6955 * energy of all candidate jobs. If so we skip that one.
    6956 */
    6957 if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
    6958 {
    6959 /* set the earliest start time to minus one to mark that candidate to be not used */
    6960 nodedatas[idx].est = -1;
    6961 continue;
    6962 }
    6963
    6964 /* create search node */
    6965 SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
    6966
    6967 /* insert new node into the theta set and updete the envelops */
    6968 SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
    6969 assert(nnodedatas <= 2*nvars);
    6970
    6971 /* move the inserted candidates together */
    6972 leaves[ninsertcands] = leaf;
    6973 ninsertcands++;
    6974
    6975 assert(!SCIPbtIsEmpty(tree));
    6976 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
    6977 assert(rootdata != NULL);
    6978
    6979 /* check if the theta set envelops exceeds the available capacity */
    6980 if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
    6981 {
    6982 SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
    6983 (*cutoff) = TRUE;
    6984
    6985 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
    6987
    6988 break;
    6989 }
    6990 }
    6991
    6992 /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
    6993 if( *cutoff )
    6994 {
    6995 int glbenery;
    6996 int est;
    6997 int lct;
    6998
    6999 glbenery = 0;
    7000 assert( 0 <= idx );
    7001 est = nodedatas[idx].est;
    7002 lct = nodedatas[idx].lct;
    7003
    7004 /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
    7005 * which led to an overload
    7006 */
    7007 for( j = j+1; j < ncands; ++j )
    7008 {
    7010 int duration;
    7011 int glbest;
    7012 int glblct;
    7013
    7014 idx = nodedataidx[j];
    7015 nodedata = &nodedatas[idx];
    7016 assert(nodedata != NULL);
    7017
    7018 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
    7019
    7020 /* get latest start time */
    7022 glblct = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
    7023
    7024 /* check if parts of the jobs run with the time window defined by the last inserted job */
    7025 if( glbest < est )
    7026 duration -= (est - glbest);
    7027
    7028 if( glblct > lct )
    7029 duration -= (glblct - lct);
    7030
    7031 if( duration > 0 )
    7032 {
    7033 glbenery += nodedata->demand * duration;
    7034
    7035 if( explanation != NULL )
    7036 explanation[nodedata->idx] = TRUE;
    7037 }
    7038 }
    7039
    7040 /* analyze the overload */
    7041 SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
    7042 conshdlrdata->usebdwidening, initialized, explanation) );
    7043 }
    7044 else if( ninsertcands > 1 && conshdlrdata->efinfer )
    7045 {
    7046 /* if we have more than one job insterted and edge-finding should be performed we do it */
    7047 SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
    7048 propest, shift, initialized, explanation, nchgbds, cutoff) );
    7049 }
    7050
    7051 /* free theta tree */
    7052 SCIPbtFree(&tree);
    7053
    7054 /* free buffer arrays */
    7055 SCIPfreeBufferArray(scip, &leaves);
    7056 SCIPfreeBufferArray(scip, &nodedataidx);
    7057 SCIPfreeBufferArray(scip, &nodedatas);
    7058
    7059 return SCIP_OKAY;
    7060}
    7061
    7062/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
    7063 *
    7064 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
    7065 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
    7066 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
    7067 */
    7068static
    7070 SCIP* scip, /**< SCIP data structure */
    7071 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7072 int nvars, /**< number of start time variables (activities) */
    7073 SCIP_VAR** vars, /**< array of start time variables */
    7074 int* durations, /**< array of durations */
    7075 int* demands, /**< array of demands */
    7076 int capacity, /**< cumulative capacity */
    7077 int hmin, /**< left bound of time axis to be considered (including hmin) */
    7078 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    7079 SCIP_CONS* cons, /**< constraint which is propagated */
    7080 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    7081 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    7082 int* nchgbds, /**< pointer to store the number of bound changes */
    7083 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    7084 )
    7085{
    7086 /* check if a cutoff was already detected */
    7087 if( (*cutoff) )
    7088 return SCIP_OKAY;
    7089
    7090 /* check if at least the basic overload checking should be preformed */
    7091 if( !conshdlrdata->efcheck )
    7092 return SCIP_OKAY;
    7093
    7094 /* check for overload, which may result in a cutoff */
    7095 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    7096 cons, TRUE, initialized, explanation, nchgbds, cutoff) );
    7097
    7098 /* check if a cutoff was detected */
    7099 if( (*cutoff) )
    7100 return SCIP_OKAY;
    7101
    7102 /* check if bound should be infer */
    7103 if( !conshdlrdata->efinfer )
    7104 return SCIP_OKAY;
    7105
    7106 /* check for overload, which may result in a cutoff */
    7107 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    7108 cons, FALSE, initialized, explanation, nchgbds, cutoff) );
    7109
    7110 return SCIP_OKAY;
    7111}
    7112
    7113/** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
    7114 * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
    7115 * event points
    7116 */
    7117static
    7119 SCIP* scip, /**< SCIP data structure */
    7120 int nvars, /**< number of start time variables (activities) */
    7121 SCIP_VAR** vars, /**< array of start time variables */
    7122 int* durations, /**< array of durations */
    7123 int* demands, /**< array of demands */
    7124 int capacity, /**< cumulative capacity */
    7125 int hmin, /**< left bound of time axis to be considered (including hmin) */
    7126 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    7127 SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
    7128 )
    7129{
    7130 SCIP_VAR* var;
    7131 int* starttimes; /* stores when each job is starting */
    7132 int* endtimes; /* stores when each job ends */
    7133 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    7134 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    7135
    7136 int lb;
    7137 int ub;
    7138 int freecapacity; /* remaining capacity */
    7139 int curtime; /* point in time which we are just checking */
    7140 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    7141 int njobs;
    7142 int j;
    7143
    7144 assert(scip != NULL);
    7145 assert(redundant != NULL);
    7146
    7147 (*redundant) = TRUE;
    7148
    7149 /* if no activities are associated with this cumulative then this constraint is redundant */
    7150 if( nvars == 0 )
    7151 return SCIP_OKAY;
    7152
    7153 assert(vars != NULL);
    7154
    7155 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    7156 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    7157 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    7158 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    7159
    7160 njobs = 0;
    7161
    7162 /* assign variables, start and endpoints to arrays */
    7163 for( j = 0; j < nvars; ++j )
    7164 {
    7165 assert(durations[j] > 0);
    7166 assert(demands[j] > 0);
    7167
    7168 var = vars[j];
    7169 assert(var != NULL);
    7170
    7173
    7174 /* check if jobs runs completely outside of the effective time horizon */
    7175 if( lb >= hmax || ub <= hmin - durations[j] )
    7176 continue;
    7177
    7178 starttimes[njobs] = MAX(lb, hmin);
    7179 startindices[njobs] = j;
    7180
    7181 endtimes[njobs] = MIN(ub == INT_MAX ? ub : ub + durations[j], hmax);
    7182 endindices[njobs] = j;
    7183 assert(starttimes[njobs] <= endtimes[njobs]);
    7184 njobs++;
    7185 }
    7186
    7187 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
    7188 SCIPsortIntInt(starttimes, startindices, njobs);
    7189 SCIPsortIntInt(endtimes, endindices, njobs);
    7190
    7191 endindex = 0;
    7192 freecapacity = capacity;
    7193
    7194 /* check each start point of a job whether the capacity is violated or not */
    7195 for( j = 0; j < njobs; ++j )
    7196 {
    7197 curtime = starttimes[j];
    7198
    7199 /* stop checking, if time point is above hmax */
    7200 if( curtime >= hmax )
    7201 break;
    7202
    7203 /* subtract all capacity needed up to this point */
    7204 freecapacity -= demands[startindices[j]];
    7205 while( j+1 < njobs && starttimes[j+1] == curtime )
    7206 {
    7207 ++j;
    7208 freecapacity -= demands[startindices[j]];
    7209 }
    7210
    7211 /* free all capacity usages of jobs the are no longer running */
    7212 while( endtimes[endindex] <= curtime )
    7213 {
    7214 freecapacity += demands[endindices[endindex]];
    7215 ++endindex;
    7216 }
    7217 assert(freecapacity <= capacity);
    7218
    7219 /* check freecapacity to be smaller than zero */
    7220 if( freecapacity < 0 && curtime >= hmin )
    7221 {
    7222 (*redundant) = FALSE;
    7223 break;
    7224 }
    7225 } /*lint --e{850}*/
    7226
    7227 /* free all buffer arrays */
    7228 SCIPfreeBufferArray(scip, &endindices);
    7229 SCIPfreeBufferArray(scip, &startindices);
    7230 SCIPfreeBufferArray(scip, &endtimes);
    7231 SCIPfreeBufferArray(scip, &starttimes);
    7232
    7233 return SCIP_OKAY;
    7234}
    7235
    7236/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
    7237 * completion time
    7238 */
    7239static
    7241 SCIP* scip, /**< SCIP data structure */
    7242 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7243 SCIP_PROFILE* profile, /**< resource profile */
    7244 int nvars, /**< number of variables (jobs) */
    7245 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    7246 int* durations, /**< array containing corresponding durations */
    7247 int* demands, /**< array containing corresponding demands */
    7248 int capacity, /**< cumulative capacity */
    7249 int hmin, /**< left bound of time axis to be considered (including hmin) */
    7250 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    7251 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    7252 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    7253 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    7254 )
    7255{
    7256 int v;
    7257
    7258 /* insert all cores */
    7259 for( v = 0; v < nvars; ++v )
    7260 {
    7261 SCIP_VAR* var;
    7262 SCIP_Bool infeasible;
    7263 int duration;
    7264 int demand;
    7265 int begin;
    7266 int end;
    7267 int est;
    7268 int lst;
    7269 int pos;
    7270
    7271 var = vars[v];
    7272 assert(var != NULL);
    7275
    7276 duration = durations[v];
    7277 assert(duration > 0);
    7278
    7279 demand = demands[v];
    7280 assert(demand > 0);
    7281
    7282 /* collect earliest and latest start time */
    7285
    7286 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
    7287 if( lst + duration <= hmin || est >= hmax )
    7288 continue;
    7289
    7290 /* compute core interval w.r.t. effective time horizon */
    7291 begin = MAX(hmin, lst);
    7292 end = MIN(hmax, est + duration);
    7293
    7294 /* check if a core exists */
    7295 if( begin >= end )
    7296 continue;
    7297
    7298 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
    7299 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
    7300
    7301 /* insert the core into core resource profile (complexity O(log n)) */
    7302 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
    7303
    7304 /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
    7305 if( infeasible )
    7306 {
    7307 assert(begin <= SCIPprofileGetTime(profile, pos));
    7308 assert(end > SCIPprofileGetTime(profile, pos));
    7309
    7310 /* use conflict analysis to analysis the core insertion which was infeasible */
    7311 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    7312 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
    7313
    7314 if( explanation != NULL )
    7315 explanation[v] = TRUE;
    7316
    7317 (*cutoff) = TRUE;
    7318
    7319 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    7321
    7322 break;
    7323 }
    7324 }
    7325
    7326 return SCIP_OKAY;
    7327}
    7328
    7329/** propagate the cumulative condition */
    7330static
    7332 SCIP* scip, /**< SCIP data structure */
    7333 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7334 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
    7335 int nvars, /**< number of start time variables (activities) */
    7336 SCIP_VAR** vars, /**< array of start time variables */
    7337 int* durations, /**< array of durations */
    7338 int* demands, /**< array of demands */
    7339 int capacity, /**< cumulative capacity */
    7340 int hmin, /**< left bound of time axis to be considered (including hmin) */
    7341 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    7342 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
    7343 int* nchgbds, /**< pointer to store the number of bound changes */
    7344 SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
    7345 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    7346 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    7347 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    7348 )
    7349{
    7350 SCIP_PROFILE* profile;
    7351
    7352 SCIP_RETCODE retcode = SCIP_OKAY;
    7353
    7354 assert(nchgbds != NULL);
    7355 assert(initialized != NULL);
    7356 assert(cutoff != NULL);
    7357 assert(!(*cutoff));
    7358
    7359 /**@todo avoid always sorting the variable array */
    7360
    7361 /* check if the constraint is redundant */
    7362 SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
    7363
    7364 if( *redundant )
    7365 return SCIP_OKAY;
    7366
    7367 /* create an empty resource profile for profiling the cores of the jobs */
    7368 SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
    7369
    7370 /* create core profile (compulsory parts) */
    7371 SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
    7372 initialized, explanation, cutoff), TERMINATE );
    7373
    7374 /* propagate the job cores until nothing else can be detected */
    7375 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    7376 {
    7377 SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
    7378 nchgbds, initialized, explanation, cutoff), TERMINATE );
    7379 }
    7380
    7381 /* run edge finding propagator */
    7382 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    7383 {
    7384 SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    7385 cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
    7386 }
    7387
    7388 /* run time-table edge-finding propagator */
    7389 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    7390 {
    7391 SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
    7392 nchgbds, initialized, explanation, cutoff), TERMINATE );
    7393 }
    7394 /* free resource profile */
    7395TERMINATE:
    7396 SCIPprofileFree(&profile);
    7397
    7398 return retcode;
    7399}
    7400
    7401/** propagate the cumulative constraint */
    7402static
    7404 SCIP* scip, /**< SCIP data structure */
    7405 SCIP_CONS* cons, /**< constraint to propagate */
    7406 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7407 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
    7408 int* nchgbds, /**< pointer to store the number of bound changes */
    7409 int* ndelconss, /**< pointer to store the number of deleted constraints */
    7410 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    7411 )
    7412{
    7413 SCIP_CONSDATA* consdata;
    7414 SCIP_Bool initialized;
    7415 SCIP_Bool redundant;
    7416 int oldnchgbds;
    7417
    7418 assert(scip != NULL);
    7419 assert(cons != NULL);
    7420
    7421 consdata = SCIPconsGetData(cons);
    7422 assert(consdata != NULL);
    7423
    7424 oldnchgbds = *nchgbds;
    7425 initialized = FALSE;
    7426 redundant = FALSE;
    7427
    7428 if( SCIPconsIsDeleted(cons) )
    7429 {
    7430 assert(SCIPinProbing(scip));
    7431 return SCIP_OKAY;
    7432 }
    7433
    7434 /* if the constraint marked to be propagated, do nothing */
    7435 if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
    7436 return SCIP_OKAY;
    7437
    7438 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
    7439 consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
    7440 consdata->hmin, consdata->hmax, cons,
    7441 nchgbds, &redundant, &initialized, NULL, cutoff) );
    7442
    7443 if( redundant )
    7444 {
    7445 SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
    7446 SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
    7447
    7448 if( !SCIPinProbing(scip) )
    7449 {
    7451 (*ndelconss)++;
    7452 }
    7453 }
    7454 else
    7455 {
    7456 if( initialized )
    7457 {
    7458 /* run conflict analysis since it was initialized */
    7459 assert(*cutoff == TRUE);
    7460 SCIPdebugMsg(scip, "start conflict analysis\n");
    7462 }
    7463
    7464 /* if successful, reset age of constraint */
    7465 if( *cutoff || *nchgbds > oldnchgbds )
    7466 {
    7468 }
    7469 else
    7470 {
    7471 /* mark the constraint to be propagated */
    7472 consdata->propagated = TRUE;
    7473 }
    7474 }
    7475
    7476 return SCIP_OKAY;
    7477}
    7478
    7479/** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
    7480 * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
    7481 * be realize as domain reduction. Otherwise we do nothing
    7482 */
    7483static
    7485 SCIP* scip, /**< SCIP data structure */
    7486 SCIP_VAR** vars, /**< problem variables */
    7487 int nvars, /**< number of problem variables */
    7488 int probingpos, /**< variable number to apply probing on */
    7489 SCIP_Real leftub, /**< upper bound of probing variable in left branch */
    7490 SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
    7491 SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
    7492 SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
    7493 SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
    7494 SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
    7495 SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
    7496 SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
    7497 SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
    7498 SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
    7499 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
    7500 SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
    7501 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    7502 )
    7503{
    7504 SCIP_VAR* var;
    7505 SCIP_Bool tightened;
    7506
    7507 assert(probingpos >= 0);
    7508 assert(probingpos < nvars);
    7509 assert(success != NULL);
    7510 assert(cutoff != NULL);
    7511
    7512 var = vars[probingpos];
    7513 assert(var != NULL);
    7514 assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
    7515 assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
    7516 assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
    7517 assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
    7518
    7519 (*success) = FALSE;
    7520
    7522 return SCIP_OKAY;
    7523
    7524 /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
    7525 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
    7526 leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
    7527
    7528 if( (*cutoff) )
    7529 {
    7530 /* note that cutoff may occur if presolving has not been executed fully */
    7531 SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
    7532
    7533 if( tightened )
    7534 {
    7535 (*success) =TRUE;
    7536 (*nfixedvars)++;
    7537 }
    7538
    7539 return SCIP_OKAY;
    7540 }
    7541
    7542 /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
    7543 * presolving has not been executed fully
    7544 */
    7545 if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
    7546 {
    7547 /* note that cutoff may occur if presolving has not been executed fully */
    7548 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
    7549
    7550 if( tightened )
    7551 {
    7552 (*success) = TRUE;
    7553 (*nfixedvars)++;
    7554 }
    7555
    7556 return SCIP_OKAY;
    7557 }
    7558
    7559 /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
    7560 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
    7561 rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
    7562
    7563 if( (*cutoff) )
    7564 {
    7565 /* note that cutoff may occur if presolving has not been executed fully */
    7566 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
    7567
    7568 if( tightened )
    7569 {
    7570 (*success) =TRUE;
    7571 (*nfixedvars)++;
    7572 }
    7573
    7574 return SCIP_OKAY;
    7575 }
    7576
    7577 return SCIP_OKAY;
    7578}
    7579
    7580/** is it possible, to round variable down w.r.t. objective function */
    7581static
    7583 SCIP* scip, /**< SCIP data structure */
    7584 SCIP_VAR* var, /**< problem variable */
    7585 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
    7586 )
    7587{
    7588 SCIP_Real objval;
    7589 int scalar;
    7590
    7591 assert(roundable != NULL);
    7592
    7593 *roundable = TRUE;
    7594
    7595 /* a fixed variable can be definition always be safely rounded */
    7597 return SCIP_OKAY;
    7598
    7599 /* in case the variable is not active we need to check the object coefficient of the active variable */
    7600 if( !SCIPvarIsActive(var) )
    7601 {
    7602 SCIP_VAR* actvar;
    7603 int constant;
    7604
    7605 actvar = var;
    7606
    7607 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
    7608 assert(scalar != 0);
    7609
    7610 objval = scalar * SCIPvarGetObj(actvar);
    7611 } /*lint !e438*/
    7612 else
    7613 {
    7614 scalar = 1;
    7615 objval = SCIPvarGetObj(var);
    7616 }
    7617
    7618 /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
    7619 * (the transformed problem is always a minimization problem)
    7620 *
    7621 * @note that we need to check this condition w.r.t. active variable space
    7622 */
    7623 if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
    7624 *roundable = FALSE;
    7625
    7626 return SCIP_OKAY;
    7627}
    7628
    7629/** is it possible, to round variable up w.r.t. objective function */
    7630static
    7632 SCIP* scip, /**< SCIP data structure */
    7633 SCIP_VAR* var, /**< problem variable */
    7634 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
    7635 )
    7636{
    7637 SCIP_Real objval;
    7638 int scalar;
    7639
    7640 assert(roundable != NULL);
    7641
    7642 *roundable = TRUE;
    7643
    7644 /* a fixed variable can be definition always be safely rounded */
    7646 return SCIP_OKAY;
    7647
    7648 /* in case the variable is not active we need to check the object coefficient of the active variable */
    7649 if( !SCIPvarIsActive(var) )
    7650 {
    7651 SCIP_VAR* actvar;
    7652 int constant;
    7653
    7654 actvar = var;
    7655
    7656 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
    7657 assert(scalar != 0);
    7658
    7659 objval = scalar * SCIPvarGetObj(actvar);
    7660 } /*lint !e438*/
    7661 else
    7662 {
    7663 scalar = 1;
    7664 objval = SCIPvarGetObj(var);
    7665 }
    7666
    7667 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
    7668 * (the transformed problem is always a minimization problem)
    7669 *
    7670 * @note that we need to check this condition w.r.t. active variable space
    7671 */
    7672 if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
    7673 *roundable = FALSE;
    7674
    7675 return SCIP_OKAY;
    7676}
    7677
    7678/** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
    7679 * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
    7680 * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
    7681 * the only one locking this variable in the corresponding direction.
    7682 */
    7683static
    7685 SCIP* scip, /**< SCIP data structure */
    7686 SCIP_CONS** conss, /**< array of cumulative constraint constraints */
    7687 int nconss, /**< number of cumulative constraints */
    7688 SCIP_Bool local, /**< use local bounds effective horizon? */
    7689 int* alternativelbs, /**< alternative lower bounds */
    7690 int* alternativeubs, /**< alternative lower bounds */
    7691 int* downlocks, /**< number of constraints with down lock participating by the computation */
    7692 int* uplocks /**< number of constraints with up lock participating by the computation */
    7693 )
    7694{
    7695 int nvars;
    7696 int c;
    7697 int v;
    7698
    7699 for( c = 0; c < nconss; ++c )
    7700 {
    7701 SCIP_CONSDATA* consdata;
    7702 SCIP_CONS* cons;
    7703 SCIP_VAR* var;
    7704 int hmin;
    7705 int hmax;
    7706
    7707 cons = conss[c];
    7708 assert(cons != NULL);
    7709
    7710 /* ignore constraints which are already deletet and those which are not check constraints */
    7711 if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
    7712 continue;
    7713
    7714 consdata = SCIPconsGetData(cons);
    7715 assert(consdata != NULL);
    7716 assert(consdata->nvars > 1);
    7717
    7718 /* compute the hmin and hmax */
    7719 if( local )
    7720 {
    7721 SCIP_PROFILE* profile;
    7722 SCIP_RETCODE retcode;
    7723
    7724 /* create empty resource profile with infinity resource capacity */
    7725 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
    7726
    7727 /* create worst case resource profile */
    7728 retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
    7729
    7730 hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
    7731 hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
    7732
    7733 /* free worst case profile */
    7734 SCIPprofileFree(&profile);
    7735
    7736 if( retcode != SCIP_OKAY )
    7737 return retcode;
    7738 }
    7739 else
    7740 {
    7741 hmin = consdata->hmin;
    7742 hmax = consdata->hmax;
    7743 }
    7744
    7745 consdata = SCIPconsGetData(cons);
    7746 assert(consdata != NULL);
    7747
    7748 nvars = consdata->nvars;
    7749
    7750 for( v = 0; v < nvars; ++v )
    7751 {
    7752 int scalar;
    7753 int constant;
    7754 int idx;
    7755
    7756 var = consdata->vars[v];
    7757 assert(var != NULL);
    7758
    7759 /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
    7761
    7762 /* ignore variable locally fixed variables */
    7763 if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
    7764 continue;
    7765
    7766 SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
    7767 idx = SCIPvarGetProbindex(var);
    7768 assert(idx >= 0);
    7769
    7770 /* first check lower bound fixing */
    7771 if( consdata->downlocks[v] )
    7772 {
    7773 int ect;
    7774 int est;
    7775
    7776 /* the variable has a down locked */
    7777 est = scalar * boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
    7778 ect = est + consdata->durations[v];
    7779
    7780 if( ect <= hmin || hmin >= hmax )
    7781 downlocks[idx]++;
    7782 else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
    7783 {
    7784 alternativelbs[idx] = (hmin + 1 - constant) / scalar;
    7785 downlocks[idx]++;
    7786 }
    7787 }
    7788
    7789 /* second check upper bound fixing */
    7790 if( consdata->uplocks[v] )
    7791 {
    7792 int duration;
    7793 int lct;
    7794 int lst;
    7795
    7796 duration = consdata->durations[v];
    7797
    7798 /* the variable has a up lock locked */
    7799 lst = scalar * boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
    7800 lct = lst + duration;
    7801
    7802 if( lst >= hmax || hmin >= hmax )
    7803 uplocks[idx]++;
    7804 else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
    7805 {
    7806 alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
    7807 uplocks[idx]++;
    7808 }
    7809 }
    7810 }
    7811 }
    7812
    7813 return SCIP_OKAY;
    7814}
    7815
    7816/** apply all fixings which are given by the alternative bounds */
    7817static
    7819 SCIP* scip, /**< SCIP data structure */
    7820 SCIP_VAR** vars, /**< array of active variables */
    7821 int nvars, /**< number of active variables */
    7822 int* alternativelbs, /**< alternative lower bounds */
    7823 int* alternativeubs, /**< alternative lower bounds */
    7824 int* downlocks, /**< number of constraints with down lock participating by the computation */
    7825 int* uplocks, /**< number of constraints with up lock participating by the computation */
    7826 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
    7827 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    7828 )
    7829{
    7830 SCIP_Real* downimpllbs;
    7831 SCIP_Real* downimplubs;
    7832 SCIP_Real* downproplbs;
    7833 SCIP_Real* downpropubs;
    7834 SCIP_Real* upimpllbs;
    7835 SCIP_Real* upimplubs;
    7836 SCIP_Real* upproplbs;
    7837 SCIP_Real* uppropubs;
    7838 int v;
    7839
    7840 /* get temporary memory for storing probing results */
    7841 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
    7842 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
    7843 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
    7844 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
    7845 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
    7846 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
    7847 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
    7848 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
    7849
    7850 for( v = 0; v < nvars; ++v )
    7851 {
    7852 SCIP_VAR* var;
    7853 SCIP_Bool infeasible;
    7854 SCIP_Bool fixed;
    7855 SCIP_Bool roundable;
    7856 int ub;
    7857 int lb;
    7858
    7859 var = vars[v];
    7860 assert(var != NULL);
    7861
    7862 /* ignore variables for which no alternative bounds have been computed */
    7863 if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
    7864 continue;
    7865
    7868
    7869 /* ignore fixed variables */
    7870 if( ub - lb <= 0 )
    7871 continue;
    7872
    7873 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
    7874 {
    7875 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
    7876
    7877 if( roundable )
    7878 {
    7879 if( alternativelbs[v] > ub )
    7880 {
    7881 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
    7882 assert(!infeasible);
    7883 assert(fixed);
    7884
    7885 (*nfixedvars)++;
    7886
    7887 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
    7888 * constraints
    7889 */
    7891 }
    7892 else
    7893 {
    7894 SCIP_Bool success;
    7895
    7896 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
    7897 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
    7898 * infeasible we can apply the dual reduction; otherwise we do nothing
    7899 */
    7900 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
    7901 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
    7902 nfixedvars, &success, cutoff) );
    7903
    7904 if( success )
    7905 {
    7907 }
    7908 }
    7909 }
    7910 }
    7911
    7914
    7915 /* ignore fixed variables */
    7916 if( ub - lb <= 0 )
    7917 continue;
    7918
    7919 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
    7920 {
    7921 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
    7922
    7923 if( roundable )
    7924 {
    7925 if( alternativeubs[v] < lb )
    7926 {
    7927 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
    7928 assert(!infeasible);
    7929 assert(fixed);
    7930
    7931 (*nfixedvars)++;
    7932
    7933 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
    7934 * constraints
    7935 */
    7937 }
    7938 else
    7939 {
    7940 SCIP_Bool success;
    7941
    7942 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
    7943 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
    7944 * infeasible we can apply the dual reduction; otherwise we do nothing
    7945 */
    7946 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
    7947 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
    7948 nfixedvars, &success, cutoff) );
    7949
    7950 if( success )
    7951 {
    7953 }
    7954 }
    7955 }
    7956 }
    7957 }
    7958
    7959 /* free temporary memory */
    7960 SCIPfreeBufferArray(scip, &uppropubs);
    7961 SCIPfreeBufferArray(scip, &upproplbs);
    7962 SCIPfreeBufferArray(scip, &upimplubs);
    7963 SCIPfreeBufferArray(scip, &upimpllbs);
    7964 SCIPfreeBufferArray(scip, &downpropubs);
    7965 SCIPfreeBufferArray(scip, &downproplbs);
    7966 SCIPfreeBufferArray(scip, &downimplubs);
    7967 SCIPfreeBufferArray(scip, &downimpllbs);
    7968
    7969 return SCIP_OKAY;
    7970}
    7971
    7972/** propagate all constraints together */
    7973static
    7975 SCIP* scip, /**< SCIP data structure */
    7976 SCIP_CONS** conss, /**< all cumulative constraint */
    7977 int nconss, /**< number of cumulative constraints */
    7978 SCIP_Bool local, /**< use local bounds effective horizon? */
    7979 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
    7980 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
    7981 SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
    7982 )
    7983{ /*lint --e{715}*/
    7984 SCIP_VAR** vars;
    7985 int* downlocks;
    7986 int* uplocks;
    7987 int* alternativelbs;
    7988 int* alternativeubs;
    7989 int oldnfixedvars;
    7990 int nvars;
    7991 int v;
    7992
    7994 return SCIP_OKAY;
    7995
    7996 nvars = SCIPgetNVars(scip);
    7997 oldnfixedvars = *nfixedvars;
    7998
    7999 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
    8000 SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
    8001 SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
    8002 SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
    8003 SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
    8004
    8005 /* initialize arrays */
    8006 for( v = 0; v < nvars; ++v )
    8007 {
    8008 downlocks[v] = 0;
    8009 uplocks[v] = 0;
    8010 alternativelbs[v] = INT_MAX;
    8011 alternativeubs[v] = INT_MIN;
    8012 }
    8013
    8014 /* compute alternative bounds */
    8015 SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
    8016
    8017 /* apply fixing which result of the alternative bounds directly */
    8018 SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
    8019 nfixedvars, cutoff) );
    8020
    8021 if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
    8022 {
    8023 SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
    8024 }
    8025
    8026 /* free all buffers */
    8027 SCIPfreeBufferArray(scip, &alternativeubs);
    8028 SCIPfreeBufferArray(scip, &alternativelbs);
    8029 SCIPfreeBufferArray(scip, &uplocks);
    8030 SCIPfreeBufferArray(scip, &downlocks);
    8031 SCIPfreeBufferArray(scip, &vars);
    8032
    8033 return SCIP_OKAY;
    8034}
    8035
    8036/**@} */
    8037
    8038/**@name Linear relaxations
    8039 *
    8040 * @{
    8041 */
    8042
    8043/** creates covering cuts for jobs violating resource constraints */
    8044static
    8046 SCIP* scip, /**< SCIP data structure */
    8047 SCIP_CONS* cons, /**< constraint to be checked */
    8048 int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
    8049 int time /**< at this point in time covering constraints are valid */
    8050 )
    8051{
    8052 SCIP_CONSDATA* consdata;
    8053 SCIP_ROW* row;
    8054 int* flexibleids;
    8055 int* demands;
    8056
    8057 char rowname[SCIP_MAXSTRLEN];
    8058
    8059 int remainingcap;
    8060 int smallcoversize; /* size of a small cover */
    8061 int bigcoversize; /* size of a big cover */
    8062 int nvars;
    8063
    8064 int nflexible;
    8065 int sumdemand; /* demand of all jobs up to a certain index */
    8066 int j;
    8067
    8068 assert(cons != NULL);
    8069
    8070 /* get constraint data structure */
    8071 consdata = SCIPconsGetData(cons);
    8072 assert(consdata != NULL );
    8073
    8074 nvars = consdata->nvars;
    8075
    8076 /* sort jobs according to demands */
    8077 SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
    8078 SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
    8079
    8080 nflexible = 0;
    8081 remainingcap = consdata->capacity;
    8082
    8083 /* get all jobs intersecting point 'time' with their bounds */
    8084 for( j = 0; j < nvars; ++j )
    8085 {
    8086 int ub;
    8087
    8088 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
    8089
    8090 /* only add jobs to array if they intersect with point 'time' */
    8091 if( startvalues[j] <= time && ub + consdata->durations[j] > time )
    8092 {
    8093 /* if job is fixed, capacity has to be decreased */
    8094 if( startvalues[j] == ub )
    8095 {
    8096 remainingcap -= consdata->demands[j];
    8097 }
    8098 else
    8099 {
    8100 demands[nflexible] = consdata->demands[j];
    8101 flexibleids[nflexible] = j;
    8102 ++nflexible;
    8103 }
    8104 }
    8105 }
    8106 assert(remainingcap >= 0);
    8107
    8108 /* sort demands and job ids */
    8109 SCIPsortIntInt(demands, flexibleids, nflexible);
    8110
    8111 /*
    8112 * version 1:
    8113 * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
    8114 * erzeuge cover constraint
    8115 *
    8116 */
    8117
    8118 /* find maximum number of jobs that can run in parallel (-->coversize = j) */
    8119 sumdemand = 0;
    8120 j = 0;
    8121
    8122 while( j < nflexible && sumdemand <= remainingcap )
    8123 {
    8124 sumdemand += demands[j];
    8125 j++;
    8126 }
    8127
    8128 /* j jobs form a conflict, set coversize to 'j - 1' */
    8129 bigcoversize = j-1;
    8130 assert(sumdemand > remainingcap);
    8131 assert(bigcoversize < nflexible);
    8132
    8133 /* - create a row for all jobs and their binary variables.
    8134 * - at most coversize many binary variables of jobs can be set to one
    8135 */
    8136
    8137 /* construct row name */
    8138 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
    8139 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
    8140 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
    8142
    8143 for( j = 0; j < nflexible; ++j )
    8144 {
    8145 SCIP_VAR** binvars;
    8146 SCIP_Real* vals;
    8147 int nbinvars;
    8148 int idx;
    8149 int start;
    8150 int end;
    8151 int lb;
    8152 int ub;
    8153 int b;
    8154
    8155 idx = flexibleids[j];
    8156
    8157 /* get and add binvars into var array */
    8158 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
    8159 assert(nbinvars != 0);
    8160
    8161 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
    8162 assert(vals != NULL);
    8163
    8164 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
    8165 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
    8166
    8167 /* compute start and finishing time */
    8168 start = time - consdata->durations[idx] + 1;
    8169 end = MIN(time, ub);
    8170
    8171 /* add all neccessary binary variables */
    8172 for( b = 0; b < nbinvars; ++b )
    8173 {
    8174 if( vals[b] < start || vals[b] < lb )
    8175 continue;
    8176
    8177 if( vals[b] > end )
    8178 break;
    8179
    8180 assert(binvars[b] != NULL);
    8181 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
    8182 }
    8183 }
    8184
    8185 /* insert and release row */
    8187
    8188 if( consdata->bcoverrowssize == 0 )
    8189 {
    8190 consdata->bcoverrowssize = 10;
    8191 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
    8192 }
    8193 if( consdata->nbcoverrows == consdata->bcoverrowssize )
    8194 {
    8195 consdata->bcoverrowssize *= 2;
    8196 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
    8197 }
    8198
    8199 consdata->bcoverrows[consdata->nbcoverrows] = row;
    8200 consdata->nbcoverrows++;
    8201
    8202 /*
    8203 * version 2:
    8204 * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
    8205 * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
    8206 */
    8207 /* find maximum number of jobs that can run in parallel (= coversize -1) */
    8208 sumdemand = 0;
    8209 j = nflexible -1;
    8210 while( sumdemand <= remainingcap )
    8211 {
    8212 assert(j >= 0);
    8213 sumdemand += demands[j];
    8214 j--;
    8215 }
    8216
    8217 smallcoversize = nflexible - (j + 1) - 1;
    8218 while( j > 0 && demands[j] == demands[nflexible-1] )
    8219 --j;
    8220
    8221 assert(smallcoversize < nflexible);
    8222
    8223 if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
    8224 {
    8225 /* construct row name */
    8226 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
    8227 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
    8228 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
    8230
    8231 /* filter binary variables for each unfixed job */
    8232 for( j = j + 1; j < nflexible; ++j )
    8233 {
    8234 SCIP_VAR** binvars;
    8235 SCIP_Real* vals;
    8236 int nbinvars;
    8237 int idx;
    8238 int start;
    8239 int end;
    8240 int lb;
    8241 int ub;
    8242 int b;
    8243
    8244 idx = flexibleids[j];
    8245
    8246 /* get and add binvars into var array */
    8247 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
    8248 assert(nbinvars != 0);
    8249
    8250 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
    8251 assert(vals != NULL);
    8252
    8253 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
    8254 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
    8255
    8256 /* compute start and finishing time */
    8257 start = time - consdata->durations[idx] + 1;
    8258 end = MIN(time, ub);
    8259
    8260 /* add all neccessary binary variables */
    8261 for( b = 0; b < nbinvars; ++b )
    8262 {
    8263 if( vals[b] < start || vals[b] < lb )
    8264 continue;
    8265
    8266 if( vals[b] > end )
    8267 break;
    8268
    8269 assert(binvars[b] != NULL);
    8270 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
    8271 }
    8272 }
    8273
    8274 /* insert and release row */
    8276 if( consdata->scoverrowssize == 0 )
    8277 {
    8278 consdata->scoverrowssize = 10;
    8279 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
    8280 }
    8281 if( consdata->nscoverrows == consdata->scoverrowssize )
    8282 {
    8283 consdata->scoverrowssize *= 2;
    8284 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
    8285 }
    8286
    8287 consdata->scoverrows[consdata->nscoverrows] = row;
    8288 consdata->nscoverrows++;
    8289 }
    8290
    8291 /* free buffer arrays */
    8292 SCIPfreeBufferArray(scip, &flexibleids);
    8293 SCIPfreeBufferArray(scip, &demands);
    8294
    8295 return SCIP_OKAY;
    8296}
    8297
    8298/** method to construct cover cuts for all points in time */
    8299static
    8301 SCIP* scip, /**< SCIP data structure */
    8302 SCIP_CONS* cons /**< constraint to be separated */
    8303 )
    8304{
    8305 SCIP_CONSDATA* consdata;
    8306
    8307 int* startvalues; /* stores when each job is starting */
    8308 int* endvalues; /* stores when each job ends */
    8309 int* startvaluessorted; /* stores when each job is starting */
    8310 int* endvaluessorted; /* stores when each job ends */
    8311 int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
    8312 int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
    8313
    8314 int nvars; /* number of jobs for this constraint */
    8315 int freecapacity; /* remaining capacity */
    8316 int curtime; /* point in time which we are just checking */
    8317 int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    8318
    8319 int hmin;
    8320 int hmax;
    8321
    8322 int j;
    8323 int t;
    8324
    8325 assert(scip != NULL);
    8326 assert(cons != NULL);
    8327
    8328 consdata = SCIPconsGetData(cons);
    8329 assert(consdata != NULL);
    8330
    8331 /* if no activities are associated with this resource then this constraint is redundant */
    8332 if( consdata->vars == NULL )
    8333 return SCIP_OKAY;
    8334
    8335 nvars = consdata->nvars;
    8336 hmin = consdata->hmin;
    8337 hmax = consdata->hmax;
    8338
    8339 SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
    8340 SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
    8341 SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
    8342 SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
    8343 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    8344 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    8345
    8346 /* assign start and endpoints to arrays */
    8347 for ( j = 0; j < nvars; ++j )
    8348 {
    8349 startvalues[j] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
    8350 startvaluessorted[j] = startvalues[j];
    8351
    8352 endvalues[j] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
    8353 endvaluessorted[j] = endvalues[j];
    8354
    8355 startindices[j] = j;
    8356 endindices[j] = j;
    8357 }
    8358
    8359 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
    8360 * (and sort the indices in the same way) */
    8361 SCIPsortIntInt(startvaluessorted, startindices, nvars);
    8362 SCIPsortIntInt(endvaluessorted, endindices, nvars);
    8363
    8364 endidx = 0;
    8365 freecapacity = consdata->capacity;
    8366
    8367 /* check each startpoint of a job whether the capacity is kept or not */
    8368 for( j = 0; j < nvars; ++j )
    8369 {
    8370 curtime = startvaluessorted[j];
    8371 if( curtime >= hmax )
    8372 break;
    8373
    8374 /* subtract all capacity needed up to this point */
    8375 freecapacity -= consdata->demands[startindices[j]];
    8376
    8377 while( j+1 < nvars && startvaluessorted[j+1] == curtime )
    8378 {
    8379 ++j;
    8380 freecapacity -= consdata->demands[startindices[j]];
    8381 }
    8382
    8383 /* free all capacity usages of jobs the are no longer running */
    8384 while( endidx < nvars && curtime >= endvaluessorted[endidx] )
    8385 {
    8386 freecapacity += consdata->demands[endindices[endidx]];
    8387 ++endidx;
    8388 }
    8389
    8390 assert(freecapacity <= consdata->capacity);
    8391 assert(endidx <= nvars);
    8392
    8393 /* --> endindex - points to the next job which will finish
    8394 * j - points to the last job that has been released
    8395 */
    8396
    8397 /* check freecapacity to be smaller than zero
    8398 * then we will add cover constraints to the MIP
    8399 */
    8400 if( freecapacity < 0 && curtime >= hmin )
    8401 {
    8402 int nextprofilechange;
    8403
    8404 /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
    8405 if( j < nvars-1 )
    8406 nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
    8407 else
    8408 nextprofilechange = endvaluessorted[endidx];
    8409
    8410 nextprofilechange = MIN(nextprofilechange, hmax);
    8411
    8412 for( t = curtime; t < nextprofilechange; ++t )
    8413 {
    8414 SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
    8415
    8416 /* create covering constraint */
    8417 SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
    8418 }
    8419 } /* end if freecapacity > 0 */
    8420 } /*lint --e{850}*/
    8421
    8422 consdata->covercuts = TRUE;
    8423
    8424 /* free all buffer arrays */
    8425 SCIPfreeBufferArray(scip, &endindices);
    8426 SCIPfreeBufferArray(scip, &startindices);
    8427 SCIPfreeBufferArray(scip, &endvaluessorted);
    8428 SCIPfreeBufferArray(scip, &startvaluessorted);
    8429 SCIPfreeBufferArray(scip, &endvalues);
    8430 SCIPfreeBufferArray(scip, &startvalues);
    8431
    8432 return SCIP_OKAY;
    8433}
    8434
    8435/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
    8436 * constraint
    8437 */
    8438static
    8440 SCIP* scip, /**< SCIP data structure */
    8441 SCIP_CONS* cons, /**< constraint to be checked */
    8442 int* startindices, /**< permutation with rspect to the start times */
    8443 int curtime, /**< current point in time */
    8444 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    8445 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    8446 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
    8447 )
    8448{
    8449 SCIP_CONSDATA* consdata;
    8450 SCIP_VAR** binvars;
    8451 int* coefs;
    8452 int nbinvars;
    8453 char name[SCIP_MAXSTRLEN];
    8454 int capacity;
    8455 int b;
    8456
    8457 assert(nstarted > nfinished);
    8458
    8459 consdata = SCIPconsGetData(cons);
    8460 assert(consdata != NULL);
    8461 assert(consdata->nvars > 0);
    8462
    8463 capacity = consdata->capacity;
    8464 assert(capacity > 0);
    8465
    8466 nbinvars = 0;
    8467 SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
    8468
    8469 /* construct row name */
    8470 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
    8471
    8472 if( cutsasconss )
    8473 {
    8474 SCIP_CONS* lincons;
    8475
    8476 /* create knapsack constraint for the given time point */
    8477 SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
    8479
    8480 for( b = 0; b < nbinvars; ++b )
    8481 {
    8482 SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
    8483 }
    8484
    8485 /* add and release the new constraint */
    8486 SCIP_CALL( SCIPaddCons(scip, lincons) );
    8487 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
    8488 }
    8489 else
    8490 {
    8491 SCIP_ROW* row;
    8492
    8493 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
    8495
    8496 for( b = 0; b < nbinvars; ++b )
    8497 {
    8498 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
    8499 }
    8500
    8503
    8504 if( consdata->demandrowssize == 0 )
    8505 {
    8506 consdata->demandrowssize = 10;
    8507 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
    8508 }
    8509 if( consdata->ndemandrows == consdata->demandrowssize )
    8510 {
    8511 consdata->demandrowssize *= 2;
    8512 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
    8513 }
    8514
    8515 consdata->demandrows[consdata->ndemandrows] = row;
    8516 consdata->ndemandrows++;
    8517 }
    8518
    8519 SCIPfreeBufferArrayNull(scip, &binvars);
    8521
    8522 return SCIP_OKAY;
    8523}
    8524
    8525/** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
    8526 * row
    8527 */
    8528static
    8530 SCIP* scip, /**< SCIP data structure */
    8531 SCIP_CONS* cons, /**< constraint to be checked */
    8532 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
    8533 )
    8534{
    8535 SCIP_CONSDATA* consdata;
    8536
    8537 int* starttimes; /* stores when each job is starting */
    8538 int* endtimes; /* stores when each job ends */
    8539 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    8540 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    8541
    8542 int nvars; /* number of activities for this constraint */
    8543 int freecapacity; /* remaining capacity */
    8544 int curtime; /* point in time which we are just checking */
    8545 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    8546
    8547 int hmin;
    8548 int hmax;
    8549
    8550 int j;
    8551
    8552 assert(scip != NULL);
    8553 assert(cons != NULL);
    8554
    8555 consdata = SCIPconsGetData(cons);
    8556 assert(consdata != NULL);
    8557
    8558 nvars = consdata->nvars;
    8559
    8560 /* if no activities are associated with this cumulative then this constraint is redundant */
    8561 if( nvars == 0 )
    8562 return SCIP_OKAY;
    8563
    8564 assert(consdata->vars != NULL);
    8565
    8566 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    8567 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    8568 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    8569 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    8570
    8571 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
    8572 SCIPconsGetName(cons), nvars);
    8573
    8574 /* create event point arrays */
    8575 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
    8576 starttimes, endtimes, startindices, endindices, FALSE);
    8577
    8578 endindex = 0;
    8579 freecapacity = consdata->capacity;
    8580 hmin = consdata->hmin;
    8581 hmax = consdata->hmax;
    8582
    8583 /* check each startpoint of a job whether the capacity is kept or not */
    8584 for( j = 0; j < nvars; ++j )
    8585 {
    8586 curtime = starttimes[j];
    8587 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
    8588
    8589 if( curtime >= hmax )
    8590 break;
    8591
    8592 /* remove the capacity requirments for all job which start at the curtime */
    8593 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
    8594
    8595 /* add the capacity requirments for all job which end at the curtime */
    8596 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
    8597
    8598 assert(freecapacity <= consdata->capacity);
    8599 assert(endindex <= nvars);
    8600
    8601 /* endindex - points to the next job which will finish */
    8602 /* j - points to the last job that has been released */
    8603
    8604 /* if free capacity is smaller than zero, then add rows to the LP */
    8605 if( freecapacity < 0 && curtime >= hmin )
    8606 {
    8607 int nextstarttime;
    8608 int t;
    8609
    8610 /* step forward until next job is released and see whether capacity constraint is met or not */
    8611 if( j < nvars-1 )
    8612 nextstarttime = starttimes[j+1];
    8613 else
    8614 nextstarttime = endtimes[nvars-1];
    8615
    8616 nextstarttime = MIN(nextstarttime, hmax);
    8617
    8618 /* create capacity restriction row for current event point */
    8619 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
    8620
    8621 /* create for all points in time between the current event point and next start event point a row if the free
    8622 * capacity is still smaller than zero */
    8623 for( t = curtime+1 ; t < nextstarttime; ++t )
    8624 {
    8625 /* add the capacity requirments for all job which end at the curtime */
    8626 addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
    8627
    8628 if( freecapacity < 0 )
    8629 {
    8630 /* add constraint */
    8631 SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
    8632
    8633 /* create capacity restriction row */
    8634 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
    8635 }
    8636 else
    8637 break;
    8638 }
    8639 }
    8640 } /*lint --e{850}*/
    8641
    8642 /* free all buffer arrays */
    8643 SCIPfreeBufferArray(scip, &endindices);
    8644 SCIPfreeBufferArray(scip, &startindices);
    8645 SCIPfreeBufferArray(scip, &endtimes);
    8646 SCIPfreeBufferArray(scip, &starttimes);
    8647
    8648 return SCIP_OKAY;
    8649}
    8650
    8651/** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
    8652 * capacity is larger than the capacity of the cumulative constraint
    8653 * - for each necessary point in time:
    8654 *
    8655 * sum_j sum_t demand_j * x_{j,t} <= capacity
    8656 *
    8657 * where x(j,t) is the binary variables of job j at time t
    8658 */
    8659static
    8661 SCIP* scip, /**< SCIP data structure */
    8662 SCIP_CONS* cons, /**< cumulative constraint */
    8663 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
    8664 )
    8665{
    8666 SCIP_CONSDATA* consdata;
    8667
    8668 consdata = SCIPconsGetData(cons);
    8669 assert(consdata != NULL);
    8670 assert(consdata->demandrows == NULL);
    8671 assert(consdata->ndemandrows == 0);
    8672
    8673 /* collect the linking constraints */
    8674 if( consdata->linkingconss == NULL )
    8675 {
    8677 }
    8678
    8679 SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
    8680
    8681 /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
    8682 if( cutsasconss )
    8683 {
    8684 if( SCIPconsIsInitial(cons) )
    8685 {
    8687 }
    8688 if( SCIPconsIsSeparated(cons) )
    8689 {
    8691 }
    8692 if( SCIPconsIsEnforced(cons) )
    8693 {
    8695 }
    8696 }
    8697
    8698 return SCIP_OKAY;
    8699}
    8700
    8701/** adds linear relaxation of cumulative constraint to the LP */
    8702static
    8704 SCIP* scip, /**< SCIP data structure */
    8705 SCIP_CONS* cons, /**< cumulative constraint */
    8706 SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
    8707 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
    8708 )
    8709{
    8710 SCIP_CONSDATA* consdata;
    8711 int r;
    8712
    8713 consdata = SCIPconsGetData(cons);
    8714 assert(consdata != NULL);
    8715
    8716 if( consdata->demandrows == NULL )
    8717 {
    8718 assert(consdata->ndemandrows == 0);
    8719
    8720 SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
    8721
    8722 return SCIP_OKAY;
    8723 }
    8724
    8725 for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
    8726 {
    8727 if( !SCIProwIsInLP(consdata->demandrows[r]) )
    8728 {
    8729 assert(consdata->demandrows[r] != NULL);
    8730 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
    8731 }
    8732 }
    8733
    8734 return SCIP_OKAY;
    8735}
    8736
    8737/** checks constraint for violation, and adds it as a cut if possible */
    8738static
    8740 SCIP* scip, /**< SCIP data structure */
    8741 SCIP_CONS* cons, /**< cumulative constraint to be separated */
    8742 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    8743 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
    8744 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
    8745 )
    8746{ /*lint --e{715}*/
    8747 SCIP_CONSDATA* consdata;
    8748 int ncuts;
    8749 int r;
    8750
    8751 assert(scip != NULL);
    8752 assert(cons != NULL);
    8753 assert(separated != NULL);
    8754 assert(cutoff != NULL);
    8755
    8756 *separated = FALSE;
    8757 *cutoff = FALSE;
    8758
    8759 consdata = SCIPconsGetData(cons);
    8760 assert(consdata != NULL);
    8761
    8762 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
    8763
    8764 if( consdata->demandrows == NULL )
    8765 {
    8766 assert(consdata->ndemandrows == 0);
    8767
    8769
    8770 return SCIP_OKAY;
    8771 }
    8772
    8773 ncuts = 0;
    8774
    8775 /* check each row that is not contained in LP */
    8776 for( r = 0; r < consdata->ndemandrows; ++r )
    8777 {
    8778 if( !SCIProwIsInLP(consdata->demandrows[r]) )
    8779 {
    8780 SCIP_Real feasibility;
    8781
    8782 if( sol != NULL )
    8783 feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
    8784 else
    8785 feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
    8786
    8787 if( SCIPisFeasNegative(scip, feasibility) )
    8788 {
    8789 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
    8790 if ( *cutoff )
    8791 {
    8793 return SCIP_OKAY;
    8794 }
    8795 *separated = TRUE;
    8796 ncuts++;
    8797 }
    8798 }
    8799 }
    8800
    8801 if( ncuts > 0 )
    8802 {
    8803 SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
    8804
    8805 /* if successful, reset age of constraint */
    8807 (*separated) = TRUE;
    8808 }
    8809
    8810 return SCIP_OKAY;
    8811}
    8812
    8813/** checks constraint for violation, and adds it as a cut if possible */
    8814static
    8816 SCIP* scip, /**< SCIP data structure */
    8817 SCIP_CONS* cons, /**< logic or constraint to be separated */
    8818 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    8819 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
    8820 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
    8821 )
    8822{
    8823 SCIP_CONSDATA* consdata;
    8824 SCIP_ROW* row;
    8825 SCIP_Real minfeasibility;
    8826 int r;
    8827
    8828 assert(scip != NULL);
    8829 assert(cons != NULL);
    8830 assert(separated != NULL);
    8831 assert(cutoff != NULL);
    8832
    8833 *separated = FALSE;
    8834 *cutoff = FALSE;
    8835
    8836 consdata = SCIPconsGetData(cons);
    8837 assert(consdata != NULL);
    8838
    8839 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
    8840
    8841 /* collect the linking constraints */
    8842 if( consdata->linkingconss == NULL )
    8843 {
    8845 }
    8846
    8847 if( !consdata->covercuts )
    8848 {
    8849 SCIP_CALL( createCoverCuts(scip, cons) );
    8850 }
    8851
    8852 row = NULL;
    8853 minfeasibility = SCIPinfinity(scip);
    8854
    8855 /* check each row of small covers that is not contained in LP */
    8856 for( r = 0; r < consdata->nscoverrows; ++r )
    8857 {
    8858 if( !SCIProwIsInLP(consdata->scoverrows[r]) )
    8859 {
    8860 SCIP_Real feasibility;
    8861
    8862 assert(consdata->scoverrows[r] != NULL);
    8863 if( sol != NULL )
    8864 feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
    8865 else
    8866 feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
    8867
    8868 if( minfeasibility > feasibility )
    8869 {
    8870 minfeasibility = feasibility;
    8871 row = consdata->scoverrows[r];
    8872 }
    8873 }
    8874 }
    8875
    8876 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
    8877
    8878 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
    8879 {
    8880 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
    8881 SCIPconsGetName(cons), minfeasibility);
    8882
    8883 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    8885 if ( *cutoff )
    8886 return SCIP_OKAY;
    8887 (*separated) = TRUE;
    8888 }
    8889
    8890 minfeasibility = SCIPinfinity(scip);
    8891 row = NULL;
    8892
    8893 /* check each row of small covers that is not contained in LP */
    8894 for( r = 0; r < consdata->nbcoverrows; ++r )
    8895 {
    8896 if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
    8897 {
    8898 SCIP_Real feasibility;
    8899
    8900 assert(consdata->bcoverrows[r] != NULL);
    8901 if( sol != NULL )
    8902 feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
    8903 else
    8904 feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
    8905
    8906 if( minfeasibility > feasibility )
    8907 {
    8908 minfeasibility = feasibility;
    8909 row = consdata->bcoverrows[r];
    8910 }
    8911 }
    8912 }
    8913
    8914 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
    8915
    8916 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
    8917 {
    8918 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
    8919 SCIPconsGetName(cons), minfeasibility);
    8920
    8921 assert(row != NULL);
    8922 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    8924 if ( *cutoff )
    8925 return SCIP_OKAY;
    8926 (*separated) = TRUE;
    8927 }
    8928
    8929 return SCIP_OKAY;
    8930}
    8931
    8932/** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
    8933static
    8935 SCIP* scip, /**< SCIP data structure */
    8936 SCIP_CONS* cons, /**< constraint to be checked */
    8937 int* startindices, /**< permutation with rspect to the start times */
    8938 int curtime, /**< current point in time */
    8939 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    8940 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    8941 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
    8942 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
    8943 )
    8944{
    8945 SCIP_CONSDATA* consdata;
    8946 char name[SCIP_MAXSTRLEN];
    8947 int lhs; /* left hand side of constraint */
    8948
    8949 SCIP_VAR** activevars;
    8950 SCIP_ROW* row;
    8951
    8952 int v;
    8953
    8954 assert(nstarted > nfinished);
    8955
    8956 consdata = SCIPconsGetData(cons);
    8957 assert(consdata != NULL);
    8958 assert(consdata->nvars > 0);
    8959
    8960 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
    8961
    8962 SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
    8963
    8964 if( lower )
    8965 {
    8966 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
    8967
    8968 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
    8969 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
    8970 }
    8971 else
    8972 {
    8973 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
    8974 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
    8975 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
    8976 }
    8977
    8979
    8980 for( v = 0; v < nstarted - nfinished; ++v )
    8981 {
    8982 SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
    8983 }
    8984
    8987
    8988 SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
    8989
    8990 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    8991
    8992 /* free buffers */
    8993 SCIPfreeBufferArrayNull(scip, &activevars);
    8994
    8995 return SCIP_OKAY;
    8996}
    8997
    8998/** checks constraint for violation, and adds it as a cut if possible */
    8999static
    9001 SCIP* scip, /**< SCIP data structure */
    9002 SCIP_CONS* cons, /**< cumulative constraint to be separated */
    9003 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    9004 SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
    9005 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
    9006 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
    9007 )
    9008{
    9009 SCIP_CONSDATA* consdata;
    9010
    9011 int* starttimes; /* stores when each job is starting */
    9012 int* endtimes; /* stores when each job ends */
    9013 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    9014 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    9015
    9016 int nvars; /* number of activities for this constraint */
    9017 int freecapacity; /* remaining capacity */
    9018 int curtime; /* point in time which we are just checking */
    9019 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    9020
    9021 int hmin;
    9022 int hmax;
    9023 int j;
    9024
    9025 assert(scip != NULL);
    9026 assert(cons != NULL);
    9027
    9028 consdata = SCIPconsGetData(cons);
    9029 assert(consdata != NULL);
    9030
    9031 nvars = consdata->nvars;
    9032
    9033 /* if no activities are associated with this cumulative then this constraint is redundant */
    9034 if( nvars <= 1 )
    9035 return SCIP_OKAY;
    9036
    9037 assert(consdata->vars != NULL);
    9038
    9039 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    9040 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    9041 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    9042 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    9043
    9044 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
    9045 SCIPconsGetName(cons), nvars);
    9046
    9047 /* create event point arrays */
    9048 createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
    9049
    9050 /* now nvars might be smaller than before! */
    9051
    9052 endindex = 0;
    9053 freecapacity = consdata->capacity;
    9054 hmin = consdata->hmin;
    9055 hmax = consdata->hmax;
    9056
    9057 /* check each startpoint of a job whether the capacity is kept or not */
    9058 for( j = 0; j < nvars && !(*cutoff); ++j )
    9059 {
    9060 curtime = starttimes[j];
    9061
    9062 if( curtime >= hmax )
    9063 break;
    9064
    9065 /* remove the capacity requirements for all job which start at the curtime */
    9066 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
    9067
    9068 /* add the capacity requirments for all job which end at the curtime */
    9069 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
    9070
    9071 assert(freecapacity <= consdata->capacity);
    9072 assert(endindex <= nvars);
    9073
    9074 /* endindex - points to the next job which will finish */
    9075 /* j - points to the last job that has been released */
    9076
    9077 /* if free capacity is smaller than zero, then add rows to the LP */
    9078 if( freecapacity < 0 && curtime >= hmin)
    9079 {
    9080 /* create capacity restriction row for current event point */
    9081 SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
    9082 *separated = TRUE;
    9083 }
    9084 } /*lint --e{850}*/
    9085
    9086 /* free all buffer arrays */
    9087 SCIPfreeBufferArray(scip, &endindices);
    9088 SCIPfreeBufferArray(scip, &startindices);
    9089 SCIPfreeBufferArray(scip, &endtimes);
    9090 SCIPfreeBufferArray(scip, &starttimes);
    9091
    9092 return SCIP_OKAY;
    9093}
    9094
    9095/**@} */
    9096
    9097
    9098/**@name Presolving
    9099 *
    9100 * @{
    9101 */
    9102
    9103#ifndef NDEBUG
    9104/** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
    9105 * correct
    9106 */
    9107static
    9109 SCIP* scip, /**< SCIP data structure */
    9110 SCIP_CONS* cons /**< constraint to be checked */
    9111 )
    9112{
    9113 SCIP_CONSDATA* consdata;
    9114 int capacity;
    9115 int nvars;
    9116 int j;
    9117
    9118 assert(scip != NULL);
    9119 assert(cons != NULL);
    9120
    9121 consdata = SCIPconsGetData(cons);
    9122 assert(consdata != NULL);
    9123
    9124 nvars = consdata->nvars;
    9125
    9126 /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
    9127 if( nvars <= 1 )
    9128 return TRUE;
    9129
    9130 assert(consdata->vars != NULL);
    9131 capacity = consdata->capacity;
    9132
    9133 /* check each activity: if demand is larger than capacity the problem is infeasible */
    9134 for ( j = 0; j < nvars; ++j )
    9135 {
    9136 if( consdata->demands[j] > capacity )
    9137 return FALSE;
    9138 }
    9139
    9140 return TRUE;
    9141}
    9142#endif
    9143
    9144/** delete constraint if it consists of at most one job
    9145 *
    9146 * @todo this method needs to be adjusted w.r.t. effective horizon
    9147 */
    9148static
    9150 SCIP* scip, /**< SCIP data structure */
    9151 SCIP_CONS* cons, /**< constraint to propagate */
    9152 int* ndelconss, /**< pointer to store the number of deleted constraints */
    9153 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    9154 )
    9155{
    9156 SCIP_CONSDATA* consdata;
    9157
    9158 assert(scip != NULL);
    9159 assert(cons != NULL);
    9160
    9161 consdata = SCIPconsGetData(cons);
    9162 assert(consdata != NULL);
    9163
    9164 if( consdata->nvars == 0 )
    9165 {
    9166 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
    9167
    9168 SCIP_CALL( SCIPdelCons(scip, cons) );
    9169 (*ndelconss)++;
    9170 }
    9171 else if( consdata->nvars == 1 )
    9172 {
    9173 if( consdata->demands[0] > consdata->capacity )
    9174 (*cutoff) = TRUE;
    9175 else
    9176 {
    9177 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
    9178
    9179 SCIP_CALL( SCIPdelCons(scip, cons) );
    9180 (*ndelconss)++;
    9181 }
    9182 }
    9183
    9184 return SCIP_OKAY;
    9185}
    9186
    9187/** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
    9188 * this is done in the SCIP_DECL_CONSINITPRE() callback
    9189 */
    9190static
    9192 SCIP* scip, /**< SCIP data structure */
    9193 SCIP_CONS* cons /**< constraint to propagate */
    9194 )
    9195{
    9196 SCIP_CONSDATA* consdata;
    9197 SCIP_VAR* var;
    9198 int demand;
    9199 int duration;
    9200 int hmin;
    9201 int hmax;
    9202 int est;
    9203 int lct;
    9204 int j;
    9205
    9206 assert(scip != NULL);
    9207 assert(cons != NULL);
    9208
    9209 consdata = SCIPconsGetData(cons);
    9210 assert(consdata != NULL);
    9211
    9212 hmin = consdata->hmin;
    9213 hmax = consdata->hmax;
    9214
    9215 SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
    9216 SCIPconsGetName(cons), hmin, hmax);
    9217
    9218 for( j = consdata->nvars-1; j >= 0; --j )
    9219 {
    9220 var = consdata->vars[j];
    9221 demand = consdata->demands[j];
    9222 duration = consdata->durations[j];
    9223
    9224 /* earliest completion time (ect) and latest start time (lst) */
    9226 lct = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
    9227
    9228 if( demand == 0 || duration == 0 )
    9229 {
    9230 /* jobs with zero demand or zero duration can be removed */
    9231 SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
    9232 SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
    9233
    9234 /* remove variable form constraint */
    9235 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
    9236 }
    9237 else if( est >= hmax || lct <= hmin )
    9238 {
    9239 SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
    9240 SCIPvarGetName(var), est, lct - duration, duration);
    9241
    9242 /* delete variable at the given position */
    9243 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
    9244
    9245 /* for the statistic we count the number of jobs which are irrelevant */
    9247 }
    9248 }
    9249
    9250 return SCIP_OKAY;
    9251}
    9252
    9253/** adjust bounds of over sizeed job (the demand is larger than the capacity) */
    9254static
    9256 SCIP* scip, /**< SCIP data structure */
    9257 SCIP_CONSDATA* consdata, /**< constraint data */
    9258 int pos, /**< position of job in the consdata */
    9259 int* nchgbds, /**< pointer to store the number of changed bounds */
    9260 int* naddconss, /**< pointer to store the number of added constraints */
    9261 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
    9262 )
    9263{
    9264 SCIP_VAR* var;
    9265 SCIP_Bool tightened;
    9266 int duration;
    9267 int ect;
    9268 int lst;
    9269
    9270 assert(scip != NULL);
    9271
    9272 /* zero energy jobs should be removed already */
    9273 assert(consdata->durations[pos] > 0);
    9274 assert(consdata->demands[pos] > 0);
    9275
    9276 var = consdata->vars[pos];
    9277 assert(var != NULL);
    9278 duration = consdata->durations[pos];
    9279
    9280 /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
    9281 SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
    9282 SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
    9283
    9284 /* earliest completion time (ect) and latest start time (lst) */
    9285 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
    9287
    9288 /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
    9289 if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
    9290 return SCIP_OKAY;
    9291
    9292 if( ect > consdata->hmin && lst < consdata->hmax )
    9293 {
    9294 /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
    9295 *cutoff = TRUE;
    9296 }
    9297 else if( lst < consdata->hmax )
    9298 {
    9299 /* move the latest start time of this job in such a way that it finishes before or at hmin */
    9300 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
    9301 assert(tightened);
    9302 assert(!(*cutoff));
    9303 (*nchgbds)++;
    9304 }
    9305 else if( ect > consdata->hmin )
    9306 {
    9307 /* move the earliest start time of this job in such a way that it starts after or at hmax */
    9308 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
    9309 assert(tightened);
    9310 assert(!(*cutoff));
    9311 (*nchgbds)++;
    9312 }
    9313 else
    9314 {
    9315 /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
    9316 * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
    9317 *
    9318 * (var <= hmin - duration) /\ (var >= hmax)
    9319 */
    9320 SCIP_CONS* cons;
    9321
    9322 SCIP_VAR* vartuple[2];
    9323 SCIP_BOUNDTYPE boundtypetuple[2];
    9324 SCIP_Real boundtuple[2];
    9325
    9326 char name[SCIP_MAXSTRLEN];
    9327 int leftbound;
    9328 int rightbound;
    9329
    9330 leftbound = consdata->hmin - duration;
    9331 rightbound = consdata->hmax;
    9332
    9333 /* allocate temporary memory for arrays */
    9334 vartuple[0] = var;
    9335 vartuple[1] = var;
    9336 boundtuple[0] = (SCIP_Real)leftbound;
    9337 boundtuple[1] = (SCIP_Real)rightbound;
    9338 boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
    9339 boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
    9340
    9341 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
    9342 SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
    9343
    9344 /* create and add bounddisjunction constraint */
    9345 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
    9346 TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
    9347
    9349
    9350 /* add and release the new constraint */
    9351 SCIP_CALL( SCIPaddCons(scip, cons) );
    9352 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    9353 (*naddconss)++;
    9354 }
    9355
    9356 return SCIP_OKAY;
    9357}
    9358
    9359/** try to removed over sizeed jobs (the demand is larger than the capacity) */
    9360static
    9362 SCIP* scip, /**< SCIP data structure */
    9363 SCIP_CONS* cons, /**< constraint */
    9364 int* nchgbds, /**< pointer to store the number of changed bounds */
    9365 int* nchgcoefs, /**< pointer to store the number of changed coefficient */
    9366 int* naddconss, /**< pointer to store the number of added constraints */
    9367 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
    9368 )
    9369{
    9370 SCIP_CONSDATA* consdata;
    9371 int capacity;
    9372 int j;
    9373
    9374 consdata = SCIPconsGetData(cons);
    9375 assert(consdata != NULL);
    9376
    9377 /* if a cutoff was already detected just return */
    9378 if( *cutoff )
    9379 return SCIP_OKAY;
    9380
    9381 capacity = consdata->capacity;
    9382
    9383 for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
    9384 {
    9385 if( consdata->demands[j] > capacity )
    9386 {
    9387 SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
    9388
    9389 /* remove variable form constraint */
    9390 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
    9391 (*nchgcoefs)++;
    9392 }
    9393 }
    9394
    9395 SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
    9396
    9397 return SCIP_OKAY;
    9398}
    9399
    9400/** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
    9401static
    9403 SCIP* scip, /**< SCIP data structure */
    9404 SCIP_VAR* var, /**< integer variable to fix */
    9405 SCIP_Bool uplock, /**< has thet start time variable a up lock */
    9406 int* nfixedvars /**< pointer to store the number fixed variables */
    9407 )
    9408{
    9409 SCIP_Bool infeasible;
    9410 SCIP_Bool tightened;
    9411 SCIP_Bool roundable;
    9412
    9413 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
    9414 * would/could end in an implication which can lead to cutoff of the/all optimal solution
    9415 */
    9417 return SCIP_OKAY;
    9418
    9419 /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
    9420 * handler is the only one locking that variable up
    9421 */
    9422 assert(uplock == TRUE || uplock == FALSE);
    9423 assert((int)TRUE == 1); /*lint !e506*/
    9424 assert((int)FALSE == 0); /*lint !e506*/
    9425
    9426 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
    9427 return SCIP_OKAY;
    9428
    9429 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
    9430
    9431 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
    9432 * (the transformed problem is always a minimization problem)
    9433 */
    9434 if( !roundable )
    9435 return SCIP_OKAY;
    9436
    9437 SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
    9439
    9440 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
    9441 assert(!infeasible);
    9442
    9443 if( tightened )
    9444 {
    9445 SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
    9446 (*nfixedvars)++;
    9447 }
    9448
    9449 return SCIP_OKAY;
    9450}
    9451
    9452/** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
    9453static
    9455 SCIP* scip, /**< SCIP data structure */
    9456 SCIP_VAR* var, /**< integer variable to fix */
    9457 SCIP_Bool downlock, /**< has the variable a down lock */
    9458 int* nfixedvars /**< pointer to store the number fixed variables */
    9459 )
    9460{
    9461 SCIP_Bool infeasible;
    9462 SCIP_Bool tightened;
    9463 SCIP_Bool roundable;
    9464
    9465 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
    9466 * would/could end in an implication which can lead to cutoff of the/all optimal solution
    9467 */
    9469 return SCIP_OKAY;
    9470
    9471 /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
    9472 * handler is the only one locking that variable down
    9473 */
    9474 assert(downlock == TRUE || downlock == FALSE);
    9475 assert((int)TRUE == 1); /*lint !e506*/
    9476 assert((int)FALSE == 0); /*lint !e506*/
    9477
    9478 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
    9479 return SCIP_OKAY;
    9480
    9481 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
    9482
    9483 /* is it possible, to round variable down w.r.t. objective function? */
    9484 if( !roundable )
    9485 return SCIP_OKAY;
    9486
    9487 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
    9488 assert(!infeasible);
    9489
    9490 if( tightened )
    9491 {
    9492 SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
    9493 (*nfixedvars)++;
    9494 }
    9495
    9496 return SCIP_OKAY;
    9497}
    9498
    9499/** normalize cumulative condition */
    9500static
    9502 SCIP* scip, /**< SCIP data structure */
    9503 int nvars, /**< number of start time variables (activities) */
    9504 int* demands, /**< array of demands */
    9505 int* capacity, /**< pointer to store the changed cumulative capacity */
    9506 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    9507 int* nchgsides /**< pointer to count number of side changes */
    9508 )
    9509{ /*lint --e{715}*/
    9510 SCIP_Longint gcd;
    9511 int mindemand1;
    9512 int mindemand2;
    9513 int v;
    9514
    9515 if( *capacity == 1 || nvars <= 1 )
    9516 return;
    9517
    9518 assert(demands[nvars-1] <= *capacity);
    9519 assert(demands[nvars-2] <= *capacity);
    9520
    9521 gcd = (SCIP_Longint)demands[nvars-1];
    9522 mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
    9523 mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
    9524
    9525 for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
    9526 {
    9527 assert(mindemand1 <= mindemand2);
    9528 assert(demands[v] <= *capacity);
    9529
    9530 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
    9531
    9532 if( mindemand1 > demands[v] )
    9533 {
    9534 mindemand2 = mindemand1;
    9535 mindemand1 = demands[v];
    9536 }
    9537 else if( mindemand2 > demands[v] )
    9538 mindemand2 = demands[v];
    9539 }
    9540
    9541 if( mindemand1 + mindemand2 > *capacity )
    9542 {
    9543 SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
    9544
    9545 for( v = 0; v < nvars; ++v )
    9546 demands[v] = 1;
    9547
    9548 (*capacity) = 1;
    9549
    9550 (*nchgcoefs) += nvars;
    9551 (*nchgsides)++;
    9552 }
    9553 else if( gcd >= 2 )
    9554 {
    9555 SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
    9556
    9557 for( v = 0; v < nvars; ++v )
    9558 demands[v] /= (int) gcd;
    9559
    9560 (*capacity) /= (int) gcd;
    9561
    9562 (*nchgcoefs) += nvars;
    9563 (*nchgsides)++;
    9564 }
    9565}
    9566
    9567/** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
    9568 * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
    9569 * capacity since in that case none of the jobs can run in parallel
    9570 */
    9571static
    9573 SCIP* scip, /**< SCIP data structure */
    9574 SCIP_CONS* cons, /**< cumulative constraint */
    9575 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    9576 int* nchgsides /**< pointer to count number of side changes */
    9577 )
    9578{
    9579 SCIP_CONSDATA* consdata;
    9580 int capacity;
    9581
    9582 assert(nchgcoefs != NULL);
    9583 assert(nchgsides != NULL);
    9584 assert(!SCIPconsIsModifiable(cons));
    9585
    9586 consdata = SCIPconsGetData(cons);
    9587 assert(consdata != NULL);
    9588
    9589 if( consdata->normalized )
    9590 return;
    9591
    9592 capacity = consdata->capacity;
    9593
    9594 /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
    9595
    9596 normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
    9597
    9598 consdata->normalized = TRUE;
    9599
    9600 if( capacity > consdata->capacity )
    9601 consdata->varbounds = FALSE;
    9602}
    9603
    9604/** computes for the given cumulative condition the effective horizon */
    9605static
    9607 SCIP* scip, /**< SCIP data structure */
    9608 int nvars, /**< number of variables (jobs) */
    9609 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    9610 int* durations, /**< array containing corresponding durations */
    9611 int* demands, /**< array containing corresponding demands */
    9612 int capacity, /**< available cumulative capacity */
    9613 int* hmin, /**< pointer to store the left bound of the effective horizon */
    9614 int* hmax, /**< pointer to store the right bound of the effective horizon */
    9615 int* split /**< point were the cumulative condition can be split */
    9616 )
    9617{
    9618 SCIP_PROFILE* profile;
    9619
    9620 /* create empty resource profile with infinity resource capacity */
    9621 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
    9622
    9623 /* create worst case resource profile */
    9624 SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
    9625
    9626 /* print resource profile in if SCIP_DEBUG is defined */
    9628
    9629 /* computes the first time point where the resource capacity can be violated */
    9630 (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
    9631
    9632 /* computes the first time point where the resource capacity is satisfied for sure */
    9633 (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
    9634
    9635 (*split) = (*hmax);
    9636
    9637 if( *hmin < *hmax && !SCIPinRepropagation(scip) )
    9638 {
    9639 int* timepoints;
    9640 int* loads;
    9641 int ntimepoints;
    9642 int t;
    9643
    9644 /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
    9645 * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
    9646 * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
    9647 * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
    9648 * explain the certain "old" bound changes
    9649 */
    9650
    9651 /* search for time points */
    9652 ntimepoints = SCIPprofileGetNTimepoints(profile);
    9653 timepoints = SCIPprofileGetTimepoints(profile);
    9654 loads = SCIPprofileGetLoads(profile);
    9655
    9656 /* check if there exist a time point within the effective horizon [hmin,hmax) such that the capacity is not exceed w.r.t. worst case profile */
    9657 for( t = 0; t < ntimepoints; ++t )
    9658 {
    9659 /* ignore all time points before the effective horizon */
    9660 if( timepoints[t] <= *hmin )
    9661 continue;
    9662
    9663 /* ignore all time points after the effective horizon */
    9664 if( timepoints[t] >= *hmax )
    9665 break;
    9666
    9667 /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
    9668 * can split the cumulative constraint into two cumulative constraints
    9669 */
    9670 if( loads[t] <= capacity )
    9671 {
    9672 (*split) = timepoints[t];
    9673 break;
    9674 }
    9675 }
    9676 }
    9677
    9678 /* free worst case profile */
    9679 SCIPprofileFree(&profile);
    9680
    9681 return SCIP_OKAY;
    9682}
    9683
    9684/** creates and adds a cumulative constraint */
    9685static
    9687 SCIP* scip, /**< SCIP data structure */
    9688 const char* name, /**< name of constraint */
    9689 int nvars, /**< number of variables (jobs) */
    9690 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    9691 int* durations, /**< array containing corresponding durations */
    9692 int* demands, /**< array containing corresponding demands */
    9693 int capacity, /**< available cumulative capacity */
    9694 int hmin, /**< left bound of time axis to be considered (including hmin) */
    9695 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    9696 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    9697 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    9698 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    9699 * Usually set to TRUE. */
    9700 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    9701 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    9702 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    9703 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    9704 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    9705 * Usually set to TRUE. */
    9706 SCIP_Bool local, /**< is constraint only valid locally?
    9707 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    9708 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    9709 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    9710 * adds coefficients to this constraint. */
    9711 SCIP_Bool dynamic, /**< is constraint subject to aging?
    9712 * Usually set to FALSE. Set to TRUE for own cuts which
    9713 * are seperated as constraints. */
    9714 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    9715 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    9716 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    9717 * if it may be moved to a more global node?
    9718 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    9719 )
    9720{
    9721 SCIP_CONS* cons;
    9722
    9723 /* creates cumulative constraint and adds it to problem */
    9724 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
    9725 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    9726
    9727 /* adjust the effective time horizon of the new constraint */
    9728 SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
    9729 SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
    9730
    9731 /* add and release new cumulative constraint */
    9732 SCIP_CALL( SCIPaddCons(scip, cons) );
    9733 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    9734
    9735 return SCIP_OKAY;
    9736}
    9737
    9738/** computes the effective horizon and checks if the constraint can be decompsed */
    9739static
    9741 SCIP* scip, /**< SCIP data structure */
    9742 SCIP_CONS* cons, /**< cumulative constraint */
    9743 int* ndelconss, /**< pointer to store the number of deleted constraints */
    9744 int* naddconss, /**< pointer to store the number of added constraints */
    9745 int* nchgsides /**< pointer to store the number of changed sides */
    9746 )
    9747{
    9748 SCIP_CONSDATA* consdata;
    9749 int hmin;
    9750 int hmax;
    9751 int split;
    9752
    9753 consdata = SCIPconsGetData(cons);
    9754 assert(consdata != NULL);
    9755
    9756 if( consdata->nvars <= 1 )
    9757 return SCIP_OKAY;
    9758
    9759 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
    9760 consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
    9761
    9762 /* check if this time point improves the effective horizon */
    9763 if( consdata->hmin < hmin )
    9764 {
    9765 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
    9766
    9767 consdata->hmin = hmin;
    9768 (*nchgsides)++;
    9769 }
    9770
    9771 /* check if this time point improves the effective horizon */
    9772 if( consdata->hmax > hmax )
    9773 {
    9774 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
    9775 consdata->hmax = hmax;
    9776 (*nchgsides)++;
    9777 }
    9778
    9779 /* check if the constraint is redundant */
    9780 if( consdata->hmax <= consdata->hmin )
    9781 {
    9782 SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
    9783 SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
    9784
    9785 SCIP_CALL( SCIPdelCons(scip, cons) );
    9786 (*ndelconss)++;
    9787 }
    9788 else if( consdata->hmin < split && split < consdata->hmax )
    9789 {
    9790 char name[SCIP_MAXSTRLEN];
    9791 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
    9792
    9793 SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
    9794 SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
    9795
    9796 assert(split < consdata->hmax);
    9797
    9798 /* creates cumulative constraint and adds it to problem */
    9799 SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
    9800 consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
    9803
    9804 /* adjust the effective time horizon of the constraint */
    9805 consdata->hmax = split;
    9806
    9807 assert(consdata->hmin < consdata->hmax);
    9808
    9809 /* for the statistic we count the number of time we decompose a cumulative constraint */
    9811 (*naddconss)++;
    9812 }
    9813
    9814 return SCIP_OKAY;
    9815}
    9816
    9817
    9818/** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
    9819 *
    9820 * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
    9821 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
    9822 *
    9823 * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
    9824 * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
    9825 * down-lock of the corresponding start time variable can be removed.
    9826 *
    9827 * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
    9828 * locking the corresponding variable down, and the objective coefficient of the start time variable is not
    9829 * negative, than the job can be dual fixed to its earlier start time (est).
    9830 *
    9831 * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
    9832 * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
    9833 * removing the values {est+1,...,hmin} form variable domain is dual feasible.
    9834 *
    9835 * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
    9836 * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
    9837 * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
    9838 * form variable domain is dual feasible.
    9839 *
    9840 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
    9841 * the cumulative condition; The deletion has to be done later.
    9842 */
    9843static
    9845 SCIP* scip, /**< SCIP data structure */
    9846 int nvars, /**< number of start time variables (activities) */
    9847 SCIP_VAR** vars, /**< array of start time variables */
    9848 int* durations, /**< array of durations */
    9849 int hmin, /**< left bound of time axis to be considered (including hmin) */
    9850 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    9851 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
    9852 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
    9853 SCIP_CONS* cons, /**< underlying constraint, or NULL */
    9854 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
    9855 int* nfixedvars, /**< pointer to store the number of fixed variables */
    9856 int* nchgsides, /**< pointer to store the number of changed sides */
    9857 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    9858 )
    9859{
    9860 SCIP_Real* downimpllbs;
    9861 SCIP_Real* downimplubs;
    9862 SCIP_Real* downproplbs;
    9863 SCIP_Real* downpropubs;
    9864 SCIP_Real* upimpllbs;
    9865 SCIP_Real* upimplubs;
    9866 SCIP_Real* upproplbs;
    9867 SCIP_Real* uppropubs;
    9868
    9869 int firstminect;
    9870 int secondminect;
    9871 int v;
    9872
    9873 /* get temporary memory for storing probing results needed for step (4) and (5) */
    9874 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
    9875 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
    9876 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
    9877 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
    9878 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
    9879 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
    9880 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
    9881 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
    9882
    9883 assert(scip != NULL);
    9884 assert(nvars > 1);
    9885 assert(cons != NULL);
    9886
    9887 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
    9888
    9889 firstminect = INT_MAX;
    9890 secondminect = INT_MAX;
    9891
    9892 /* compute the two smallest earlier completion times; which are needed for step (5) */
    9893 for( v = 0; v < nvars; ++v )
    9894 {
    9895 int ect;
    9896
    9897 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
    9898
    9899 if( ect < firstminect )
    9900 {
    9901 secondminect = firstminect;
    9902 firstminect = ect;
    9903 }
    9904 else if( ect < secondminect )
    9905 secondminect = ect;
    9906 }
    9907
    9908 /* loop over all jobs and check if one of the 5 reductions can be applied */
    9909 for( v = 0; v < nvars; ++v )
    9910 {
    9911 SCIP_VAR* var;
    9912 int duration;
    9913
    9914 int alternativelb;
    9915 int minect;
    9916 int est;
    9917 int ect;
    9918 int lst;
    9919 int lct;
    9920
    9921 var = vars[v];
    9922 assert(var != NULL);
    9923
    9924 duration = durations[v];
    9925 assert(duration > 0);
    9926
    9927 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
    9928 * time (lct)
    9929 */
    9931 ect = est + duration;
    9933 lct = lst + duration;
    9934
    9935 /* compute the earliest completion time of all remaining jobs */
    9936 if( ect == firstminect )
    9937 minect = secondminect;
    9938 else
    9939 minect = firstminect;
    9940
    9941 /* compute potential alternative lower bound (step (4) and (5)) */
    9942 alternativelb = MAX(hmin+1, minect);
    9943 alternativelb = MIN(alternativelb, hmax);
    9944
    9945 if( lct <= hmin )
    9946 {
    9947 /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
    9948 * cumulative condition
    9949 */
    9950 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
    9951 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
    9952
    9953 /* mark variable to be irrelevant */
    9954 irrelevants[v] = TRUE;
    9955
    9956 /* for the statistic we count the number of jobs which are irrelevant */
    9958 }
    9959 else if( lst <= hmin && SCIPconsIsChecked(cons) )
    9960 {
    9961 /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
    9962 * so the down lock can be omitted
    9963 */
    9964
    9965 assert(downlocks != NULL);
    9966 assert(uplocks != NULL);
    9967
    9968 if( !uplocks[v] )
    9969 {
    9970 /* the variables has no up lock and we can also remove the down lock;
    9971 * => lst <= hmin and ect >= hmax
    9972 * => remove job and reduce capacity by the demand of that job
    9973 *
    9974 * We mark the job to be deletable. The removement together with the capacity reducion is done later
    9975 */
    9976
    9977 SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
    9978 SCIPvarGetName(var), ect - duration, lst, duration);
    9979
    9980 /* mark variable to be irrelevant */
    9981 irrelevants[v] = TRUE;
    9982
    9983 /* for the statistic we count the number of jobs which always run during the effective horizon */
    9985 }
    9986
    9987 if( downlocks[v] )
    9988 {
    9989 SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
    9990 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
    9991
    9992 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
    9993 downlocks[v] = FALSE;
    9994 (*nchgsides)++;
    9995
    9996 /* for the statistic we count the number of removed locks */
    9998 }
    9999 }
    10000 else if( ect <= hmin )
    10001 {
    10002 /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
    10003 * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
    10004 * removed form the cumulative condition after it was fixed to its earliest start time
    10005 */
    10006
    10007 /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
    10008 * bound;
    10009 */
    10010 if( downlocks != NULL && SCIPconsIsChecked(cons) )
    10011 {
    10012 /* fix integer start time variable if possible to it lower bound */
    10013 SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
    10014 }
    10015
    10016 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
    10017 {
    10018 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
    10019 SCIPvarGetName(var), ect - duration, lst, duration);
    10020
    10021 /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
    10022 assert(boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
    10023
    10024 /* mark variable to be irrelevant */
    10025 irrelevants[v] = TRUE;
    10026
    10027 /* for the statistic we count the number of jobs which are dual fixed */
    10029 }
    10030 }
    10031 else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
    10032 {
    10033 assert(downlocks != NULL);
    10034
    10035 /* check step (4) and (5) */
    10036
    10037 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
    10038 * is in favor of rounding the variable down
    10039 */
    10040 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
    10041 {
    10042 SCIP_Bool roundable;
    10043
    10044 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
    10045
    10046 if( roundable )
    10047 {
    10048 if( alternativelb > lst )
    10049 {
    10050 SCIP_Bool infeasible;
    10051 SCIP_Bool fixed;
    10052
    10053 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
    10054 assert(!infeasible);
    10055 assert(fixed);
    10056
    10057 (*nfixedvars)++;
    10058
    10059 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
    10060 * constraints
    10061 */
    10063 }
    10064 else
    10065 {
    10066 SCIP_Bool success;
    10067
    10068 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
    10069 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
    10070 * infeasible we can apply the dual reduction; otherwise we do nothing
    10071 */
    10072 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
    10073 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
    10074 nfixedvars, &success, cutoff) );
    10075
    10076 if( success )
    10077 {
    10079 }
    10080 }
    10081 }
    10082 }
    10083 }
    10084
    10085 SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
    10086 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
    10087 }
    10088
    10089 /* free temporary memory */
    10090 SCIPfreeBufferArray(scip, &uppropubs);
    10091 SCIPfreeBufferArray(scip, &upproplbs);
    10092 SCIPfreeBufferArray(scip, &upimplubs);
    10093 SCIPfreeBufferArray(scip, &upimpllbs);
    10094 SCIPfreeBufferArray(scip, &downpropubs);
    10095 SCIPfreeBufferArray(scip, &downproplbs);
    10096 SCIPfreeBufferArray(scip, &downimplubs);
    10097 SCIPfreeBufferArray(scip, &downimpllbs);
    10098
    10099 return SCIP_OKAY;
    10100}
    10101
    10102/** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
    10103 *
    10104 * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
    10105 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
    10106 *
    10107 * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
    10108 * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
    10109 * up-lock of the corresponding start time variable can be removed.
    10110 *
    10111 * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
    10112 * locking the corresponding variable up, and the objective coefficient of the start time variable is not
    10113 * positive, than the job can be dual fixed to its latest start time (lst).
    10114 *
    10115 * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
    10116 * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
    10117 * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
    10118 * of the corresponding job).
    10119
    10120 * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
    10121 * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
    10122 * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
    10123 * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
    10124 *
    10125 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
    10126 * the cumulative condition; The deletion has to be done later.
    10127 */
    10128static
    10130 SCIP* scip, /**< SCIP data structure */
    10131 int nvars, /**< number of start time variables (activities) */
    10132 SCIP_VAR** vars, /**< array of start time variables */
    10133 int* durations, /**< array of durations */
    10134 int hmin, /**< left bound of time axis to be considered (including hmin) */
    10135 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    10136 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
    10137 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
    10138 SCIP_CONS* cons, /**< underlying constraint, or NULL */
    10139 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
    10140 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
    10141 int* nchgsides, /**< pointer to store the number of changed sides */
    10142 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    10143 )
    10144{
    10145 SCIP_Real* downimpllbs;
    10146 SCIP_Real* downimplubs;
    10147 SCIP_Real* downproplbs;
    10148 SCIP_Real* downpropubs;
    10149 SCIP_Real* upimpllbs;
    10150 SCIP_Real* upimplubs;
    10151 SCIP_Real* upproplbs;
    10152 SCIP_Real* uppropubs;
    10153
    10154 int firstmaxlst;
    10155 int secondmaxlst;
    10156 int v;
    10157
    10158 /* get temporary memory for storing probing results needed for step (4) and (5) */
    10159 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
    10160 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
    10161 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
    10162 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
    10163 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
    10164 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
    10165 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
    10166 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
    10167
    10168 assert(scip != NULL);
    10169 assert(nvars > 1);
    10170 assert(cons != NULL);
    10171
    10172 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
    10173
    10174 firstmaxlst = INT_MIN;
    10175 secondmaxlst = INT_MIN;
    10176
    10177 /* compute the two largest latest start times; which are needed for step (5) */
    10178 for( v = 0; v < nvars; ++v )
    10179 {
    10180 int lst;
    10181
    10183
    10184 if( lst > firstmaxlst )
    10185 {
    10186 secondmaxlst = firstmaxlst;
    10187 firstmaxlst = lst;
    10188 }
    10189 else if( lst > secondmaxlst )
    10190 secondmaxlst = lst;
    10191 }
    10192
    10193 /* loop over all jobs and check if one of the 5 reductions can be applied */
    10194 for( v = 0; v < nvars; ++v )
    10195 {
    10196 SCIP_VAR* var;
    10197 int duration;
    10198
    10199 int alternativeub;
    10200 int maxlst;
    10201 int est;
    10202 int ect;
    10203 int lst;
    10204
    10205 var = vars[v];
    10206 assert(var != NULL);
    10207
    10208 duration = durations[v];
    10209 assert(duration > 0);
    10210
    10211 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
    10212 * time (lct)
    10213 */
    10215 ect = est + duration;
    10217
    10218 /* compute the latest start time of all remaining jobs */
    10219 if( lst == firstmaxlst )
    10220 maxlst = secondmaxlst;
    10221 else
    10222 maxlst = firstmaxlst;
    10223
    10224 /* compute potential alternative upper bound (step (4) and (5)) */
    10225 alternativeub = MIN(hmax - 1, maxlst) - duration;
    10226 alternativeub = MAX(alternativeub, hmin);
    10227
    10228 if( est >= hmax )
    10229 {
    10230 /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
    10231 * cumulative condition
    10232 */
    10233 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
    10234 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
    10235
    10236 /* mark variable to be irrelevant */
    10237 irrelevants[v] = TRUE;
    10238
    10239 /* for the statistic we count the number of jobs which are irrelevant */
    10241 }
    10242 else if( ect >= hmax && SCIPconsIsChecked(cons) )
    10243 {
    10244 assert(downlocks != NULL);
    10245 assert(uplocks != NULL);
    10246
    10247 /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
    10248 * so the up lock can be omitted
    10249 */
    10250
    10251 if( !downlocks[v] )
    10252 {
    10253 /* the variables has no down lock and we can also remove the up lock;
    10254 * => lst <= hmin and ect >= hmax
    10255 * => remove job and reduce capacity by the demand of that job
    10256 */
    10257 SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
    10258 SCIPvarGetName(var), est, lst, duration);
    10259
    10260 /* mark variable to be irrelevant */
    10261 irrelevants[v] = TRUE;
    10262
    10263 /* for the statistic we count the number of jobs which always run during the effective horizon */
    10265 }
    10266
    10267 if( uplocks[v] )
    10268 {
    10269 SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
    10270 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
    10271
    10272 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
    10273 uplocks[v] = FALSE;
    10274 (*nchgsides)++;
    10275
    10276 /* for the statistic we count the number of removed locks */
    10278 }
    10279 }
    10280 else if( lst >= hmax )
    10281 {
    10282 /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
    10283 * latest start time (which implies that it starts after the effective horizon finishes), the job can be
    10284 * removed form the cumulative condition after it was fixed to its latest start time
    10285 */
    10286
    10287 /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
    10288 * bound
    10289 */
    10290 if( uplocks != NULL && SCIPconsIsChecked(cons) )
    10291 {
    10292 /* fix integer start time variable if possible to its upper bound */
    10293 SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
    10294 }
    10295
    10296 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
    10297 {
    10298 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
    10299 SCIPvarGetName(var), est, lst, duration);
    10300
    10301 /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
    10302 assert(boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
    10303
    10304 /* mark variable to be irrelevant */
    10305 irrelevants[v] = TRUE;
    10306
    10307 /* for the statistic we count the number of jobs which are dual fixed */
    10309 }
    10310 }
    10311 else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
    10312 {
    10313 assert(uplocks != NULL);
    10314
    10315 /* check step (4) and (5) */
    10316
    10317 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
    10318 * is in favor of rounding the variable down
    10319 */
    10320 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
    10321 {
    10322 SCIP_Bool roundable;
    10323
    10324 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
    10325
    10326 if( roundable )
    10327 {
    10328 if( alternativeub < est )
    10329 {
    10330 SCIP_Bool infeasible;
    10331 SCIP_Bool fixed;
    10332
    10333 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
    10334 assert(!infeasible);
    10335 assert(fixed);
    10336
    10337 (*nfixedvars)++;
    10338
    10339 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
    10340 * constraints
    10341 */
    10343 }
    10344 else
    10345 {
    10346 SCIP_Bool success;
    10347
    10348 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
    10349 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
    10350 * in infeasible we can apply the dual reduction; otherwise we do nothing
    10351 */
    10352 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
    10353 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
    10354 nfixedvars, &success, cutoff) );
    10355
    10356 if( success )
    10357 {
    10359 }
    10360 }
    10361 }
    10362 }
    10363 }
    10364 }
    10365
    10366 /* free temporary memory */
    10367 SCIPfreeBufferArray(scip, &uppropubs);
    10368 SCIPfreeBufferArray(scip, &upproplbs);
    10369 SCIPfreeBufferArray(scip, &upimplubs);
    10370 SCIPfreeBufferArray(scip, &upimpllbs);
    10371 SCIPfreeBufferArray(scip, &downpropubs);
    10372 SCIPfreeBufferArray(scip, &downproplbs);
    10373 SCIPfreeBufferArray(scip, &downimplubs);
    10374 SCIPfreeBufferArray(scip, &downimpllbs);
    10375
    10376 return SCIP_OKAY;
    10377}
    10378
    10379/** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
    10380static
    10382 SCIP* scip, /**< SCIP data structure */
    10383 SCIP_CONS* cons, /**< cumulative constraint */
    10384 int* nfixedvars, /**< pointer to store the number of fixed variables */
    10385 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
    10386 int* nchgsides, /**< pointer to store the number of changed sides */
    10387 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
    10388 )
    10389{
    10390 SCIP_CONSDATA* consdata;
    10391 SCIP_Bool* irrelevants;
    10392 int nvars;
    10393 int v;
    10394
    10395 assert(scip != NULL);
    10396 assert(cons != NULL);
    10397 assert(!(*cutoff));
    10398
    10399 consdata = SCIPconsGetData(cons);
    10400 assert(consdata != NULL);
    10401
    10402 nvars = consdata->nvars;
    10403
    10404 if( nvars <= 1 )
    10405 return SCIP_OKAY;
    10406
    10407 SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
    10408 BMSclearMemoryArray(irrelevants, nvars);
    10409
    10410 /* presolve constraint form the earlier start time point of view */
    10411 SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
    10412 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
    10413 irrelevants, nfixedvars, nchgsides, cutoff) );
    10414
    10415 /* presolve constraint form the latest completion time point of view */
    10416 SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
    10417 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
    10418 irrelevants, nfixedvars, nchgsides, cutoff) );
    10419
    10420 /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
    10421 * order to ensure a correct behaviour
    10422 */
    10423 for( v = nvars-1; v >= 0; --v )
    10424 {
    10425 if( irrelevants[v] )
    10426 {
    10427 SCIP_VAR* var;
    10428 int ect;
    10429 int lst;
    10430
    10431 var = consdata->vars[v];
    10432 assert(var != NULL);
    10433
    10434 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
    10436
    10437 /* check if the jobs runs completely during the effective horizon */
    10438 if( lst <= consdata->hmin && ect >= consdata->hmax )
    10439 {
    10440 if( consdata->capacity < consdata->demands[v] )
    10441 {
    10442 *cutoff = TRUE;
    10443 break;
    10444 }
    10445
    10446 consdata->capacity -= consdata->demands[v];
    10447 consdata->varbounds = FALSE;
    10448 }
    10449
    10450 SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
    10451 (*nchgcoefs)++;
    10452 }
    10453 }
    10454
    10455 SCIPfreeBufferArray(scip, &irrelevants);
    10456
    10457 return SCIP_OKAY;
    10458}
    10459
    10460/** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
    10461static
    10463 SCIP* scip, /**< SCIP data structure */
    10464 SCIP_CONSDATA* consdata, /**< constraint data */
    10465 int* startindices, /**< permutation with rspect to the start times */
    10466 int curtime, /**< current point in time */
    10467 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    10468 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    10469 SCIP_Longint** demands, /**< pointer to array storing the demands */
    10470 int* ndemands /**< pointer to store the number of different demands */
    10471 )
    10472{
    10473 int startindex;
    10474 int ncountedvars;
    10475
    10476 assert(demands != NULL);
    10477 assert(ndemands != NULL);
    10478
    10479 ncountedvars = 0;
    10480 startindex = nstarted - 1;
    10481
    10482 *ndemands = 0;
    10483
    10484 /* search for the (nstarted - nfinished) jobs which are active at curtime */
    10485 while( nstarted - nfinished > ncountedvars )
    10486 {
    10487 SCIP_VAR* var;
    10488 int endtime;
    10489 int varidx;
    10490
    10491 /* collect job information */
    10492 varidx = startindices[startindex];
    10493 assert(varidx >= 0 && varidx < consdata->nvars);
    10494
    10495 var = consdata->vars[varidx];
    10496 assert(var != NULL);
    10497
    10498 endtime = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
    10499
    10500 /* check the end time of this job is larger than the curtime; in this case the job is still running */
    10501 if( endtime > curtime )
    10502 {
    10503 if( consdata->demands[varidx] < consdata->capacity )
    10504 {
    10505 (*demands)[*ndemands] = consdata->demands[varidx];
    10506 (*ndemands)++;
    10507 }
    10508 ncountedvars++;
    10509 }
    10510
    10511 startindex--;
    10512 }
    10513}
    10514
    10515/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
    10516 * constraint
    10517 */
    10518static
    10520 SCIP* scip, /**< SCIP data structure */
    10521 SCIP_CONS* cons, /**< constraint to be checked */
    10522 int* startindices, /**< permutation with rspect to the start times */
    10523 int curtime, /**< current point in time */
    10524 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    10525 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    10526 int* bestcapacity /**< pointer to store the maximum possible capacity usage */
    10527 )
    10528{
    10529 SCIP_CONSDATA* consdata;
    10530 SCIP_Longint* demands;
    10531 SCIP_Real* profits;
    10532 int* items;
    10533 int ndemands;
    10534 SCIP_Bool success;
    10535 SCIP_Real solval;
    10536 int j;
    10537 assert(nstarted > nfinished);
    10538
    10539 consdata = SCIPconsGetData(cons);
    10540 assert(consdata != NULL);
    10541 assert(consdata->nvars > 0);
    10542 assert(consdata->capacity > 0);
    10543
    10544 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
    10545 ndemands = 0;
    10546
    10547 /* get demand array to initialize knapsack problem */
    10548 collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
    10549
    10550 /* create array for profits */
    10551 SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
    10552 SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
    10553 for( j = 0; j < ndemands; ++j )
    10554 {
    10555 profits[j] = (SCIP_Real) demands[j];
    10556 items[j] = j;/* this is only a dummy value*/
    10557 }
    10558
    10559 /* solve knapsack problem and get maximum capacity usage <= capacity */
    10560 SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
    10561 items, NULL, NULL, NULL, NULL, &solval, &success) );
    10562
    10563 assert(SCIPisFeasIntegral(scip, solval));
    10564
    10565 /* store result */
    10566 *bestcapacity = boundedConvertRealToInt(scip, solval);
    10567
    10568 SCIPfreeBufferArray(scip, &items);
    10569 SCIPfreeBufferArray(scip, &profits);
    10570 SCIPfreeBufferArray(scip, &demands);
    10571
    10572 return SCIP_OKAY;
    10573}
    10574
    10575/** try to tighten the capacity
    10576 * -- using DP for knapsack, we find the maximum possible capacity usage
    10577 * -- neglects hmin and hmax, such that it is also able to check solutions globally
    10578 */
    10579static
    10581 SCIP* scip, /**< SCIP data structure */
    10582 SCIP_CONS* cons, /**< cumulative constraint */
    10583 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    10584 int* nchgsides /**< pointer to store the number of changed sides */
    10585 )
    10586{
    10587 SCIP_CONSDATA* consdata;
    10588 int* starttimes; /* stores when each job is starting */
    10589 int* endtimes; /* stores when each job ends */
    10590 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    10591 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    10592
    10593 int nvars; /* number of activities for this constraint */
    10594 int freecapacity; /* remaining capacity */
    10595 int curtime; /* point in time which we are just checking */
    10596 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    10597
    10598 int bestcapacity;
    10599
    10600 int j;
    10601
    10602 assert(scip != NULL);
    10603 assert(cons != NULL);
    10604 assert(nchgsides != NULL);
    10605
    10606 consdata = SCIPconsGetData(cons);
    10607 assert(consdata != NULL);
    10608
    10609 nvars = consdata->nvars;
    10610
    10611 /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
    10612 if( nvars <= 1 || consdata->capacity <= 1 )
    10613 return SCIP_OKAY;
    10614
    10615 assert(consdata->vars != NULL);
    10616
    10617 SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
    10618 SCIPconsGetName(cons), consdata->capacity);
    10619
    10620 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    10621 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    10622 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    10623 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    10624
    10625 /* create event point arrays */
    10626 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
    10627 starttimes, endtimes, startindices, endindices, FALSE);
    10628
    10629 bestcapacity = 1;
    10630 endindex = 0;
    10631 freecapacity = consdata->capacity;
    10632
    10633 /* check each startpoint of a job whether the capacity is kept or not */
    10634 for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
    10635 {
    10636 curtime = starttimes[j];
    10637 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
    10638
    10639 /* remove the capacity requirments for all job which start at the curtime */
    10640 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
    10641
    10642 /* add the capacity requirments for all job which end at the curtime */
    10643 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
    10644
    10645 assert(freecapacity <= consdata->capacity);
    10646 assert(endindex <= nvars);
    10647
    10648 /* endindex - points to the next job which will finish */
    10649 /* j - points to the last job that has been released */
    10650
    10651 /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
    10652 if( freecapacity < 0 )
    10653 {
    10654 int newcapacity;
    10655
    10656 newcapacity = 1;
    10657
    10658 /* get best possible upper bound on capacity usage */
    10659 SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
    10660
    10661 /* update bestcapacity */
    10662 bestcapacity = MAX(bestcapacity, newcapacity);
    10663 SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
    10664 }
    10665
    10666 /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
    10667 if( freecapacity > 0 && freecapacity != consdata->capacity )
    10668 {
    10669 bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
    10670 SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
    10671 }
    10672
    10673 /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
    10674 if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
    10675 {
    10676 /* if demands[startindices[j]] == cap then exactly that job is running */
    10677 SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
    10678 bestcapacity = consdata->capacity;
    10679 break;
    10680 }
    10681 } /*lint --e{850}*/
    10682
    10683 /* free all buffer arrays */
    10684 SCIPfreeBufferArray(scip, &endindices);
    10685 SCIPfreeBufferArray(scip, &startindices);
    10686 SCIPfreeBufferArray(scip, &endtimes);
    10687 SCIPfreeBufferArray(scip, &starttimes);
    10688
    10689 /* check whether capacity can be tightened and whether demands need to be adjusted */
    10690 if( bestcapacity < consdata->capacity )
    10691 {
    10692 SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
    10693
    10694 SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
    10695 SCIPconsGetName(cons), consdata->capacity, bestcapacity);
    10696
    10697 for( j = 0; j < nvars; ++j )
    10698 {
    10699 if( consdata->demands[j] == consdata->capacity )
    10700 {
    10701 consdata->demands[j] = bestcapacity;
    10702 (*nchgcoefs)++;
    10703 }
    10704 }
    10705
    10706 consdata->capacity = bestcapacity;
    10707 (*nchgsides)++;
    10708
    10709 SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
    10710
    10711 consdata->varbounds = FALSE;
    10712 }
    10713
    10714 return SCIP_OKAY;
    10715}
    10716
    10717
    10718/** tries to change coefficients:
    10719 * demand_j < cap && all other parallel jobs in conflict
    10720 * ==> set demand_j := cap
    10721 */
    10722static
    10724 SCIP* scip, /**< SCIP data structure */
    10725 SCIP_CONS* cons, /**< cumulative constraint */
    10726 int* nchgcoefs /**< pointer to count total number of changed coefficients */
    10727 )
    10728{
    10729 SCIP_CONSDATA* consdata;
    10730 int nvars;
    10731 int j;
    10732 int oldnchgcoefs;
    10733 int mindemand;
    10734
    10735 assert(scip != NULL);
    10736 assert(cons != NULL);
    10737 assert(nchgcoefs != NULL);
    10738
    10739 /* get constraint data for some parameter testings only! */
    10740 consdata = SCIPconsGetData(cons);
    10741 assert(consdata != NULL);
    10742
    10743 nvars = consdata->nvars;
    10744 oldnchgcoefs = *nchgcoefs;
    10745
    10746 if( nvars <= 0 )
    10747 return SCIP_OKAY;
    10748
    10749 /* PRE1:
    10750 * check all jobs j whether: r_j + r_min > capacity holds
    10751 * if so: adjust r_j to capacity
    10752 */
    10753 mindemand = consdata->demands[0];
    10754 for( j = 0; j < nvars; ++j )
    10755 {
    10756 mindemand = MIN(mindemand, consdata->demands[j]);
    10757 }
    10758
    10759 /*check each job */
    10760 for( j = 0; j < nvars; ++j )
    10761 {
    10762 if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
    10763 {
    10764 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
    10765 consdata->demands[j], consdata->capacity);
    10766 consdata->demands[j] = consdata->capacity;
    10767 (*nchgcoefs)++;
    10768 }
    10769 }
    10770
    10771 /* PRE2:
    10772 * check for each job (with d_j < cap)
    10773 * whether it is disjunctive to all others over the time horizon
    10774 */
    10775 for( j = 0; j < nvars; ++j )
    10776 {
    10777 SCIP_Bool chgcoef;
    10778 int est_j;
    10779 int lct_j;
    10780 int i;
    10781
    10782 assert(consdata->demands[j] <= consdata->capacity);
    10783
    10784 if( consdata->demands[j] == consdata->capacity )
    10785 continue;
    10786
    10787 chgcoef = TRUE;
    10788
    10789 est_j = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
    10790 lct_j = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
    10791
    10792 for( i = 0; i < nvars; ++i )
    10793 {
    10794 int est_i;
    10795 int lct_i;
    10796
    10797 if( i == j )
    10798 continue;
    10799
    10800 est_i = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
    10801 lct_i = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
    10802
    10803 if( est_i >= lct_j || est_j >= lct_i )
    10804 continue;
    10805
    10806 if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
    10807 {
    10808 chgcoef = FALSE;
    10809 break;
    10810 }
    10811 }
    10812
    10813 if( chgcoef )
    10814 {
    10815 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
    10816 consdata->demands[j], consdata->capacity);
    10817 consdata->demands[j] = consdata->capacity;
    10818 (*nchgcoefs)++;
    10819 }
    10820 }
    10821
    10822 if( (*nchgcoefs) > oldnchgcoefs )
    10823 {
    10824 SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
    10825 (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
    10826 }
    10827
    10828 return SCIP_OKAY;
    10829}
    10830
    10831#ifdef SCIP_DISABLED_CODE
    10832/* The following should work, but does not seem to be tested well. */
    10833
    10834/** try to reformulate constraint by replacing certain jobs */
    10835static
    10836SCIP_RETCODE reformulateCons(
    10837 SCIP* scip, /**< SCIP data structure */
    10838 SCIP_CONS* cons, /**< cumulative constraint */
    10839 int* naggrvars /**< pointer to store the number of aggregated variables */
    10840 )
    10841{
    10842 SCIP_CONSDATA* consdata;
    10843 int hmin;
    10844 int hmax;
    10845 int nvars;
    10846 int v;
    10847
    10848 consdata = SCIPconsGetData(cons);
    10849 assert(cons != NULL);
    10850
    10851 nvars = consdata->nvars;
    10852 assert(nvars > 1);
    10853
    10854 hmin = consdata->hmin;
    10855 hmax = consdata->hmax;
    10856 assert(hmin < hmax);
    10857
    10858 for( v = 0; v < nvars; ++v )
    10859 {
    10860 SCIP_VAR* var;
    10861 int duration;
    10862 int est;
    10863 int ect;
    10864 int lst;
    10865 int lct;
    10866
    10867 var = consdata->vars[v];
    10868 assert(var != NULL);
    10869
    10870 duration = consdata->durations[v];
    10871
    10873 ect = est + duration;
    10875 lct = lst + duration;
    10876
    10877 /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
    10878 assert(lst > hmin || ect < hmax);
    10879
    10880 if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
    10881 {
    10882 SCIP_VAR* aggrvar;
    10883 char name[SCIP_MAXSTRLEN];
    10884 SCIP_Bool infeasible;
    10885 SCIP_Bool redundant;
    10886 SCIP_Bool aggregated;
    10887 int shift;
    10888
    10889 shift = est - (hmin - lct + MIN(hmin, ect));
    10890 assert(shift > 0);
    10891 lst = hmin;
    10892 duration = hmin - lct;
    10893
    10894 SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
    10895 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
    10896
    10897 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
    10898 SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
    10900 SCIP_CALL( SCIPaddVar(scip, var) );
    10901 SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
    10902
    10903 assert(!infeasible);
    10904 assert(!redundant);
    10905 assert(aggregated);
    10906
    10907 /* replace variable */
    10908 consdata->durations[v] = duration;
    10909 consdata->vars[v] = aggrvar;
    10910
    10911 /* remove and add locks */
    10912 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
    10913 SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
    10914
    10915 SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
    10916
    10917 (*naggrvars)++;
    10918 }
    10919 }
    10920
    10921 return SCIP_OKAY;
    10922}
    10923#endif
    10924
    10925/** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
    10926static
    10928 SCIP* scip, /**< SCIP data structure */
    10929 SCIP_CONS* cons, /**< cumulative constraint */
    10930 int* naddconss /**< pointer to store the number of added constraints */
    10931 )
    10932{
    10933 SCIP_CONSDATA* consdata;
    10934 SCIP_VAR** vars;
    10935 int* durations;
    10936 int* demands;
    10937 int capacity;
    10938 int halfcapacity;
    10939 int mindemand;
    10940 int nvars;
    10941 int v;
    10942
    10943 consdata = SCIPconsGetData(cons);
    10944 assert(consdata != NULL);
    10945
    10946 capacity = consdata->capacity;
    10947
    10948 if( capacity == 1 )
    10949 return SCIP_OKAY;
    10950
    10951 SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
    10952 SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
    10953 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
    10954
    10955 halfcapacity = capacity / 2;
    10956 mindemand = consdata->capacity;
    10957 nvars = 0;
    10958
    10959 /* collect all jobs with demand larger than half of the capacity */
    10960 for( v = 0; v < consdata->nvars; ++v )
    10961 {
    10962 if( consdata->demands[v] > halfcapacity )
    10963 {
    10964 vars[nvars] = consdata->vars[v];
    10965 demands[nvars] = 1;
    10966 durations[nvars] = consdata->durations[v];
    10967 nvars++;
    10968
    10969 mindemand = MIN(mindemand, consdata->demands[v]);
    10970 }
    10971 }
    10972
    10973 if( nvars > 0 )
    10974 {
    10975 /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
    10976 * job is still to large to be scheduled in parallel
    10977 */
    10978 for( v = 0; v < consdata->nvars; ++v )
    10979 {
    10980 if( consdata->demands[v] > halfcapacity )
    10981 continue;
    10982
    10983 if( mindemand + consdata->demands[v] > capacity )
    10984 {
    10985 demands[nvars] = 1;
    10986 durations[nvars] = consdata->durations[v];
    10987 vars[nvars] = consdata->vars[v];
    10988 nvars++;
    10989
    10990 /* @todo create one cumulative constraint and look for another small demand */
    10991 break;
    10992 }
    10993 }
    10994
    10995 /* creates cumulative constraint and adds it to problem */
    10996 SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
    10998 (*naddconss)++;
    10999 }
    11000
    11001 SCIPfreeBufferArray(scip, &demands);
    11002 SCIPfreeBufferArray(scip, &durations);
    11003 SCIPfreeBufferArray(scip, &vars);
    11004
    11005 return SCIP_OKAY;
    11006}
    11007
    11008/** presolve given constraint */
    11009static
    11011 SCIP* scip, /**< SCIP data structure */
    11012 SCIP_CONS* cons, /**< cumulative constraint */
    11013 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    11014 SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
    11015 int* nfixedvars, /**< pointer to store the number of fixed variables */
    11016 int* nchgbds, /**< pointer to store the number of changed bounds */
    11017 int* ndelconss, /**< pointer to store the number of deleted constraints */
    11018 int* naddconss, /**< pointer to store the number of added constraints */
    11019 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
    11020 int* nchgsides, /**< pointer to store the number of changed sides */
    11021 SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
    11022 SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
    11023 )
    11024{
    11025 assert(!SCIPconsIsDeleted(cons));
    11026
    11027 /* only perform dual reductions on model constraints */
    11028 if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
    11029 {
    11030 /* computes the effective horizon and checks if the constraint can be decomposed */
    11031 SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
    11032
    11033 if( SCIPconsIsDeleted(cons) )
    11034 return SCIP_OKAY;
    11035
    11036 /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
    11037 * fixings (dual reductions)
    11038 */
    11039 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    11040 {
    11041 SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
    11042
    11043 if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
    11044 return SCIP_OKAY;
    11045 }
    11046
    11047 SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
    11048
    11049 if( *cutoff || SCIPconsIsDeleted(cons) )
    11050 return SCIP_OKAY;
    11051 }
    11052
    11053 /* remove jobs which have a demand larger than the capacity */
    11054 SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
    11055 assert((*cutoff) || checkDemands(scip, cons));
    11056
    11057 if( *cutoff )
    11058 return SCIP_OKAY;
    11059
    11060 if( conshdlrdata->normalize )
    11061 {
    11062 /* divide demands by their greatest common divisor */
    11063 normalizeDemands(scip, cons, nchgcoefs, nchgsides);
    11064 }
    11065
    11066 /* delete constraint with one job */
    11067 SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
    11068
    11069 if( *cutoff || SCIPconsIsDeleted(cons) )
    11070 return SCIP_OKAY;
    11071
    11072 if( conshdlrdata->coeftightening )
    11073 {
    11074 /* try to tighten the capacity */
    11075 SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
    11076
    11077 /* try to tighten the coefficients */
    11078 SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
    11079 }
    11080
    11081 assert(checkDemands(scip, cons) || *cutoff);
    11082
    11083#ifdef SCIP_DISABLED_CODE
    11084 /* The following should work, but does not seem to be tested well. */
    11085 SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
    11086#endif
    11087
    11088 return SCIP_OKAY;
    11089}
    11090
    11091/**@name TClique Graph callbacks
    11092 *
    11093 * @{
    11094 */
    11095
    11096/** tclique graph data */
    11097struct TCLIQUE_Graph
    11098{
    11099 SCIP_VAR** vars; /**< start time variables each of them is a node */
    11100 SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
    11101 SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
    11102 SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
    11103 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
    11104 int* ninarcs; /**< number if in arcs for the precedence graph */
    11105 int* noutarcs; /**< number if out arcs for the precedence graph */
    11106 int* durations; /**< for each node the duration of the corresponding job */
    11107 int nnodes; /**< number of nodes */
    11108 int size; /**< size of the array */
    11109};
    11110
    11111/** gets number of nodes in the graph */
    11112static
    11113TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
    11114{
    11115 assert(tcliquegraph != NULL);
    11116
    11117 return tcliquegraph->nnodes;
    11118}
    11119
    11120/** gets weight of nodes in the graph */
    11121static
    11122TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
    11123{
    11124 assert(tcliquegraph != NULL);
    11125
    11126 return tcliquegraph->weights;
    11127}
    11128
    11129/** returns, whether the edge (node1, node2) is in the graph */
    11130static
    11131TCLIQUE_ISEDGE(tcliqueIsedgeClique)
    11132{
    11133 assert(tcliquegraph != NULL);
    11134 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
    11135 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
    11136
    11137 /* check if an arc exits in the precedence graph */
    11138 if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
    11139 return TRUE;
    11140
    11141 /* check if an edge exits in the non-overlapping graph */
    11142 if( tcliquegraph->demandmatrix[node1][node2] )
    11143 return TRUE;
    11144
    11145 return FALSE;
    11146}
    11147
    11148/** selects all nodes from a given set of nodes which are adjacent to a given node
    11149 * and returns the number of selected nodes
    11150 */
    11151static
    11152TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
    11153{
    11154 int nadjnodes;
    11155 int i;
    11156
    11157 assert(tcliquegraph != NULL);
    11158 assert(0 <= node && node < tcliquegraph->nnodes);
    11159 assert(nnodes == 0 || nodes != NULL);
    11160 assert(adjnodes != NULL);
    11161
    11162 nadjnodes = 0;
    11163
    11164 for( i = 0; i < nnodes; i++ )
    11165 {
    11166 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
    11167 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
    11168 assert(i == 0 || nodes[i-1] < nodes[i]);
    11169
    11170 /* check if an edge exists */
    11171 if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
    11172 {
    11173 /* current node is adjacent to given node */
    11174 adjnodes[nadjnodes] = nodes[i];
    11175 nadjnodes++;
    11176 }
    11177 }
    11178
    11179 return nadjnodes;
    11180}
    11181
    11182/** generates cuts using a clique found by algorithm for maximum weight clique
    11183 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
    11184 */
    11185static
    11186TCLIQUE_NEWSOL(tcliqueNewsolClique)
    11187{ /*lint --e{715}*/
    11188 SCIPdebugMessage("####### max clique %d\n", cliqueweight);
    11189}
    11190
    11191
    11192/** @} */
    11193
    11194/** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
    11195 * job corresponding to variable bound variable (vlbvar)
    11196 *
    11197 * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
    11198 */
    11199static
    11201 SCIP* scip, /**< SCIP data structure */
    11202 SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
    11203 SCIP_Real vlbcoef, /**< variable bound coefficient */
    11204 SCIP_Real vlbconst, /**< variable bound constant */
    11205 int duration /**< duration of the variable bound variable */
    11206 )
    11207{
    11208 if( SCIPisEQ(scip, vlbcoef, 1.0) )
    11209 {
    11210 if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
    11211 {
    11212 /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
    11213 return TRUE;
    11214 }
    11215 }
    11216 else
    11217 {
    11219
    11220 bound = (duration - vlbcoef) / (vlbcoef - 1.0);
    11221
    11222 if( SCIPisLT(scip, vlbcoef, 1.0) )
    11223 {
    11224 SCIP_Real ub;
    11225
    11226 ub = SCIPvarGetUbLocal(vlbvar);
    11227
    11228 /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
    11229 if( SCIPisLE(scip, ub, bound) )
    11230 return TRUE;
    11231 }
    11232 else
    11233 {
    11234 SCIP_Real lb;
    11235
    11236 assert(SCIPisGT(scip, vlbcoef, 1.0));
    11237
    11238 lb = SCIPvarGetLbLocal(vlbvar);
    11239
    11240 /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
    11241 if( SCIPisGE(scip, lb, bound) )
    11242 return TRUE;
    11243 }
    11244 }
    11245
    11246 return FALSE;
    11247}
    11248
    11249/** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
    11250 * job corresponding to variable which is bounded (var)
    11251 *
    11252 * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
    11253 */
    11254static
    11256 SCIP* scip, /**< SCIP data structure */
    11257 SCIP_VAR* var, /**< variable which is bound from above */
    11258 SCIP_Real vubcoef, /**< variable bound coefficient */
    11259 SCIP_Real vubconst, /**< variable bound constant */
    11260 int duration /**< duration of the variable which is bounded from above */
    11261 )
    11262{
    11263 SCIP_Real vlbcoef;
    11264 SCIP_Real vlbconst;
    11265
    11266 /* convert the variable upper bound into an variable lower bound */
    11267 vlbcoef = 1.0 / vubcoef;
    11268 vlbconst = -vubconst / vubcoef;
    11269
    11270 return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
    11271}
    11272
    11273/** get the corresponding index of the given variables; this in case of an active variable the problem index and for
    11274 * others an index larger than the number if active variables
    11275 */
    11276static
    11278 SCIP* scip, /**< SCIP data structure */
    11279 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
    11280 SCIP_VAR* var, /**< variable for which we want the index */
    11281 int* idx /**< pointer to store the index */
    11282 )
    11283{
    11284 (*idx) = SCIPvarGetProbindex(var);
    11285
    11286 if( (*idx) == -1 )
    11287 {
    11288 if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
    11289 {
    11290 (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
    11291 }
    11292 else
    11293 {
    11294 int pos;
    11295 int v;
    11296
    11297 /**@todo we might want to add the aggregation path to graph */
    11298
    11299 /* check if we have to realloc memory */
    11300 if( tcliquegraph->size == tcliquegraph->nnodes )
    11301 {
    11302 int size;
    11303
    11304 size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
    11305 tcliquegraph->size = size;
    11306
    11307 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
    11308 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
    11309 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
    11310 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
    11311 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
    11312
    11313 for( v = 0; v < tcliquegraph->nnodes; ++v )
    11314 {
    11315 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
    11316 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
    11317 }
    11318 }
    11319 assert(tcliquegraph->nnodes < tcliquegraph->size);
    11320
    11321 pos = tcliquegraph->nnodes;
    11322 assert(pos >= 0);
    11323
    11324 tcliquegraph->durations[pos] = 0;
    11325 tcliquegraph->weights[pos] = 0;
    11326 tcliquegraph->vars[pos] = var;
    11327
    11328 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
    11329 BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
    11330
    11331 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
    11332 BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
    11333
    11334 SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
    11335
    11336 tcliquegraph->nnodes++;
    11337
    11338 for( v = 0; v < tcliquegraph->nnodes; ++v )
    11339 {
    11340 tcliquegraph->precedencematrix[v][pos] = 0;
    11341 tcliquegraph->demandmatrix[v][pos] = 0;
    11342 }
    11343
    11344 (*idx) = tcliquegraph->nnodes;
    11345 }
    11346 }
    11347 else
    11348 {
    11349 assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
    11350 }
    11351
    11352 assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
    11353
    11354 return SCIP_OKAY;
    11355}
    11356
    11357/** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
    11358 *
    11359 * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
    11360 * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
    11361 *
    11362 * (i) b = 1 and c >= d
    11363 * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
    11364 * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
    11365 *
    11366 */
    11367static
    11369 SCIP* scip, /**< SCIP data structure */
    11370 TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
    11371 )
    11372{
    11373 SCIP_VAR** vars;
    11374 int nvars;
    11375 int v;
    11376
    11377 vars = SCIPgetVars(scip);
    11378 nvars = SCIPgetNVars(scip);
    11379
    11380 /* try to project each arc of the variable bound graph to precedence condition */
    11381 for( v = 0; v < nvars; ++v )
    11382 {
    11383 SCIP_VAR** vbdvars;
    11384 SCIP_VAR* var;
    11385 SCIP_Real* vbdcoefs;
    11386 SCIP_Real* vbdconsts;
    11387 int nvbdvars;
    11388 int idx1;
    11389 int b;
    11390
    11391 var = vars[v];
    11392 assert(var != NULL);
    11393
    11394 SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
    11395 assert(idx1 >= 0);
    11396
    11397 if( tcliquegraph->durations[idx1] == 0 )
    11398 continue;
    11399
    11400 vbdvars = SCIPvarGetVlbVars(var);
    11401 vbdcoefs = SCIPvarGetVlbCoefs(var);
    11402 vbdconsts = SCIPvarGetVlbConstants(var);
    11403 nvbdvars = SCIPvarGetNVlbs(var);
    11404
    11405 for( b = 0; b < nvbdvars; ++b )
    11406 {
    11407 int idx2;
    11408
    11409 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
    11410 assert(idx2 >= 0);
    11411
    11412 if( tcliquegraph->durations[idx2] == 0 )
    11413 continue;
    11414
    11415 if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
    11416 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
    11417 }
    11418
    11419 vbdvars = SCIPvarGetVubVars(var);
    11420 vbdcoefs = SCIPvarGetVubCoefs(var);
    11421 vbdconsts = SCIPvarGetVubConstants(var);
    11422 nvbdvars = SCIPvarGetNVubs(var);
    11423
    11424 for( b = 0; b < nvbdvars; ++b )
    11425 {
    11426 int idx2;
    11427
    11428 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
    11429 assert(idx2 >= 0);
    11430
    11431 if( tcliquegraph->durations[idx2] == 0 )
    11432 continue;
    11433
    11434 if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
    11435 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
    11436 }
    11437
    11438 for( b = v+1; b < nvars; ++b )
    11439 {
    11440 int idx2;
    11441
    11442 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
    11443 assert(idx2 >= 0);
    11444
    11445 if( tcliquegraph->durations[idx2] == 0 )
    11446 continue;
    11447
    11448 /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
    11449 if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
    11450 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
    11451
    11452 /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
    11453 if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
    11454 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
    11455 }
    11456 }
    11457
    11458 return SCIP_OKAY;
    11459}
    11460
    11461/** compute the transitive closer of the given graph and the number of in and out arcs */
    11462static
    11464 SCIP_Bool** adjmatrix, /**< adjacent matrix */
    11465 int* ninarcs, /**< array to store the number of in arcs */
    11466 int* noutarcs, /**< array to store the number of out arcs */
    11467 int nnodes /**< number if nodes */
    11468 )
    11469{
    11470 int i;
    11471 int j;
    11472 int k;
    11473
    11474 for( i = 0; i < nnodes; ++i )
    11475 {
    11476 for( j = 0; j < nnodes; ++j )
    11477 {
    11478 if( adjmatrix[i][j] )
    11479 {
    11480 ninarcs[j]++;
    11481 noutarcs[i]++;
    11482
    11483 for( k = 0; k < nnodes; ++k )
    11484 {
    11485 if( adjmatrix[j][k] )
    11486 adjmatrix[i][k] = TRUE;
    11487 }
    11488 }
    11489 }
    11490 }
    11491}
    11492
    11493/** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
    11494static
    11496 SCIP* scip, /**< SCIP data structure */
    11497 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
    11498 SCIP_CONS** conss, /**< array of cumulative constraints */
    11499 int nconss /**< number of cumulative constraints */
    11500 )
    11501{
    11502 int c;
    11503
    11504 /* use the cumulative constraints to initialize the none overlapping graph */
    11505 for( c = 0; c < nconss; ++c )
    11506 {
    11507 SCIP_CONSDATA* consdata;
    11508 SCIP_VAR** vars;
    11509 int* demands;
    11510 int capacity;
    11511 int nvars;
    11512 int i;
    11513
    11514 consdata = SCIPconsGetData(conss[c]);
    11515 assert(consdata != NULL);
    11516
    11517 vars = consdata->vars;
    11518 demands = consdata->demands;
    11519
    11520 nvars = consdata->nvars;
    11521 capacity = consdata->capacity;
    11522
    11523 SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
    11524
    11525 /* check pairwise if two jobs have a cumulative demand larger than the capacity */
    11526 for( i = 0; i < nvars; ++i )
    11527 {
    11528 int idx1;
    11529 int j;
    11530
    11531 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
    11532 assert(idx1 >= 0);
    11533
    11534 if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
    11535 continue;
    11536
    11537 for( j = i+1; j < nvars; ++j )
    11538 {
    11539 assert(consdata->durations[j] > 0);
    11540
    11541 if( demands[i] + demands[j] > capacity )
    11542 {
    11543 int idx2;
    11544 int est1;
    11545 int est2;
    11546 int lct1;
    11547 int lct2;
    11548
    11549 /* check if the effective horizon is large enough */
    11552
    11553 /* at least one of the jobs needs to start at hmin or later */
    11554 if( est1 < consdata->hmin && est2 < consdata->hmin )
    11555 continue;
    11556
    11557 lct1 = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
    11558 lct2 = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
    11559
    11560 /* at least one of the jobs needs to finish not later then hmin */
    11561 if( lct1 > consdata->hmax && lct2 > consdata->hmax )
    11562 continue;
    11563
    11564 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
    11565 assert(idx2 >= 0);
    11566 assert(idx1 != idx2);
    11567
    11568 if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
    11569 continue;
    11570
    11571 SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
    11572
    11573 assert(tcliquegraph->durations[idx1] > 0);
    11574 assert(tcliquegraph->durations[idx2] > 0);
    11575
    11576 tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
    11577 tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
    11578 }
    11579 }
    11580 }
    11581 }
    11582
    11583 return SCIP_OKAY;
    11584}
    11585
    11586/** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
    11587 * of jobs cannot run in parallel
    11588 */
    11589static
    11591 SCIP* scip, /**< SCIP data structure */
    11592 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
    11593 SCIP_CONS** conss, /**< array of cumulative constraints */
    11594 int nconss /**< number of cumulative constraints */
    11595 )
    11596{
    11597 assert(scip != NULL);
    11598 assert(tcliquegraph != NULL);
    11599
    11600 /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
    11601 SCIP_CALL( projectVbd(scip, tcliquegraph) );
    11602
    11603 /* compute the transitive closure of the precedence graph and the number of in and out arcs */
    11604 transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
    11605
    11606 /* constraints non-overlapping graph */
    11607 SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
    11608
    11609 return SCIP_OKAY;
    11610}
    11611
    11612/** create cumulative constraint from conflict set */
    11613static
    11615 SCIP* scip, /**< SCIP data structure */
    11616 const char* name, /**< constraint name */
    11617 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
    11618 int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
    11619 int ncliquenodes /**< number of nodes in the clique */
    11620 )
    11621{
    11622 SCIP_CONS* cons;
    11623 SCIP_VAR** vars;
    11624 int* durations;
    11625 int* demands;
    11626 int v;
    11627
    11628 SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
    11629 SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
    11630 SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
    11631
    11632 SCIPsortInt(cliquenodes, ncliquenodes);
    11633
    11634 /* collect variables, durations, and demands */
    11635 for( v = 0; v < ncliquenodes; ++v )
    11636 {
    11637 durations[v] = tcliquegraph->durations[cliquenodes[v]];
    11638 assert(durations[v] > 0);
    11639 demands[v] = 1;
    11640 vars[v] = tcliquegraph->vars[cliquenodes[v]];
    11641 }
    11642
    11643 /* create (unary) cumulative constraint */
    11644 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
    11646
    11647 SCIP_CALL( SCIPaddCons(scip, cons) );
    11648 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    11649
    11650 /* free buffers */
    11651 SCIPfreeBufferArray(scip, &demands);
    11652 SCIPfreeBufferArray(scip, &durations);
    11653 SCIPfreeBufferArray(scip, &vars);
    11654
    11655 return SCIP_OKAY;
    11656}
    11657
    11658/** search for cumulative constrainst */
    11659static
    11661 SCIP* scip, /**< SCIP data structure */
    11662 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
    11663 int* naddconss /**< pointer to store the number of added constraints */
    11664 )
    11665{
    11666 TCLIQUE_STATUS tcliquestatus;
    11667 SCIP_Bool* precedencerow;
    11668 SCIP_Bool* precedencecol;
    11669 SCIP_Bool* demandrow;
    11670 SCIP_Bool* demandcol;
    11671 SCIP_HASHTABLE* covered;
    11672 int* cliquenodes;
    11673 int ncliquenodes;
    11674 int cliqueweight;
    11675 int ntreenodes;
    11676 int nnodes;
    11677 int nconss;
    11678 int v;
    11679
    11680 nnodes = tcliquegraph->nnodes;
    11681 nconss = 0;
    11682
    11683 /* initialize the weight of each job with its duration */
    11684 for( v = 0; v < nnodes; ++v )
    11685 {
    11686 tcliquegraph->weights[v] = tcliquegraph->durations[v];
    11687 }
    11688
    11689 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
    11690 SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
    11691 SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
    11692 SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
    11693 SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
    11694
    11695 /* create a hash table to store all start time variables which are already covered by at least one clique */
    11697 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
    11698
    11699 /* for each variables/job we are ... */
    11700 for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
    11701 {
    11702 char name[SCIP_MAXSTRLEN];
    11703 int c;
    11704
    11705 /* jobs with zero durations are skipped */
    11706 if( tcliquegraph->durations[v] == 0 )
    11707 continue;
    11708
    11709 /* check if the start time variable is already covered by at least one clique */
    11710 if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
    11711 continue;
    11712
    11713 SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
    11714
    11715 /* temporarily remove the connection via the precedence graph */
    11716 for( c = 0; c < nnodes; ++c )
    11717 {
    11718 precedencerow[c] = tcliquegraph->precedencematrix[v][c];
    11719 precedencecol[c] = tcliquegraph->precedencematrix[c][v];
    11720
    11721 demandrow[c] = tcliquegraph->demandmatrix[v][c];
    11722 demandcol[c] = tcliquegraph->demandmatrix[c][v];
    11723
    11724 tcliquegraph->precedencematrix[c][v] = FALSE;
    11725 tcliquegraph->precedencematrix[v][c] = FALSE;
    11726 }
    11727
    11728 /* find (heuristically) maximum cliques which includes node v */
    11729 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
    11730 tcliquegraph, tcliqueNewsolClique, NULL,
    11731 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
    11732 10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
    11733
    11734 SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
    11735
    11736 if( ncliquenodes == 1 )
    11737 continue;
    11738
    11739 /* construct constraint name */
    11740 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
    11741
    11742 SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
    11743 nconss++;
    11744
    11745 /* all start time variable to covered hash table */
    11746 for( c = 0; c < ncliquenodes; ++c )
    11747 {
    11748 SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
    11749 }
    11750
    11751 /* copy the precedence relations back */
    11752 for( c = 0; c < nnodes; ++c )
    11753 {
    11754 tcliquegraph->precedencematrix[v][c] = precedencerow[c];
    11755 tcliquegraph->precedencematrix[c][v] = precedencecol[c];
    11756
    11757 tcliquegraph->demandmatrix[v][c] = demandrow[c];
    11758 tcliquegraph->demandmatrix[c][v] = demandcol[c];
    11759 }
    11760 }
    11761
    11762 SCIPhashtableFree(&covered);
    11763
    11764 SCIPfreeBufferArray(scip, &demandcol);
    11765 SCIPfreeBufferArray(scip, &demandrow);
    11766 SCIPfreeBufferArray(scip, &precedencecol);
    11767 SCIPfreeBufferArray(scip, &precedencerow);
    11768 SCIPfreeBufferArray(scip, &cliquenodes);
    11769
    11770 (*naddconss) += nconss;
    11771
    11772 /* for the statistic we count the number added disjunctive constraints */
    11773 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
    11774
    11775 return SCIP_OKAY;
    11776}
    11777
    11778/** create precedence constraint (as variable bound constraint */
    11779static
    11781 SCIP* scip, /**< SCIP data structure */
    11782 const char* name, /**< constraint name */
    11783 SCIP_VAR* var, /**< variable x that has variable bound */
    11784 SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
    11785 int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
    11786 )
    11787{
    11788 SCIP_CONS* cons;
    11789
    11790 /* create variable bound constraint */
    11791 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
    11793
    11795
    11796 /* add constraint to problem and release it */
    11797 SCIP_CALL( SCIPaddCons(scip, cons) );
    11798 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    11799
    11800 return SCIP_OKAY;
    11801}
    11802
    11803/** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
    11804static
    11806 SCIP* scip, /**< SCIP data structure */
    11807 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
    11808 int source, /**< index of the source node */
    11809 int sink, /**< index of the sink node */
    11810 int* naddconss /**< pointer to store the number of added constraints */
    11811 )
    11812{
    11813 TCLIQUE_WEIGHT cliqueweight;
    11814 TCLIQUE_STATUS tcliquestatus;
    11815 SCIP_VAR** vars;
    11816 int* cliquenodes;
    11817 int nnodes;
    11818 int lct;
    11819 int est;
    11820 int i;
    11821
    11822 int ntreenodes;
    11823 int ncliquenodes;
    11824
    11825 /* check if source and sink are connencted */
    11826 if( !tcliquegraph->precedencematrix[source][sink] )
    11827 return SCIP_OKAY;
    11828
    11829 nnodes = tcliquegraph->nnodes;
    11830 vars = tcliquegraph->vars;
    11831
    11832 /* reset the weights to zero */
    11833 BMSclearMemoryArray(tcliquegraph->weights, nnodes);
    11834
    11835 /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
    11836 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
    11838
    11839 /* weight all jobs which run for sure between source and sink with their duration */
    11840 for( i = 0; i < nnodes; ++i )
    11841 {
    11842 SCIP_VAR* var;
    11843 int duration;
    11844
    11845 var = vars[i];
    11846 assert(var != NULL);
    11847
    11848 duration = tcliquegraph->durations[i];
    11849
    11850 if( i == source || i == sink )
    11851 {
    11852 /* source and sink are not weighted */
    11853 tcliquegraph->weights[i] = 0;
    11854 }
    11855 else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
    11856 {
    11857 /* job i runs after source and before sink */
    11858 tcliquegraph->weights[i] = duration;
    11859 }
    11860 else if( lct <= boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var))
    11861 && est >= boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
    11862 {
    11863 /* job i run in between due the bounds of the start time variables */
    11864 tcliquegraph->weights[i] = duration;
    11865 }
    11866 else
    11867 tcliquegraph->weights[i] = 0;
    11868 }
    11869
    11870 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
    11871
    11872 /* find (heuristically) maximum cliques */
    11873 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
    11874 tcliquegraph, tcliqueNewsolClique, NULL,
    11875 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
    11876 10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
    11877
    11878 if( ncliquenodes > 1 )
    11879 {
    11880 char name[SCIP_MAXSTRLEN];
    11881 int distance;
    11882
    11883 /* construct constraint name */
    11884 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
    11885
    11886 /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
    11887 * duration of the source job
    11888 */
    11889 distance = cliqueweight + tcliquegraph->durations[source];
    11890
    11891 SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
    11892 (*naddconss)++;
    11893 }
    11894
    11895 SCIPfreeBufferArray(scip, &cliquenodes);
    11896
    11897 return SCIP_OKAY;
    11898}
    11899
    11900/** search for precedence constraints
    11901 *
    11902 * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
    11903 * corresponding two jobs
    11904 */
    11905static
    11907 SCIP* scip, /**< SCIP data structure */
    11908 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
    11909 int* naddconss /**< pointer to store the number of added constraints */
    11910 )
    11911{
    11912 int* sources;
    11913 int* sinks;
    11914 int nconss;
    11915 int nnodes;
    11916 int nsources;
    11917 int nsinks;
    11918 int i;
    11919
    11920 nnodes = tcliquegraph->nnodes;
    11921 nconss = 0;
    11922
    11923 nsources = 0;
    11924 nsinks = 0;
    11925
    11928
    11929 /* first collect all sources and sinks */
    11930 for( i = 0; i < nnodes; ++i )
    11931 {
    11932 if( tcliquegraph->ninarcs[i] == 0 )
    11933 {
    11934 sources[nsources] = i;
    11935 nsources++;
    11936 }
    11937
    11938 if( tcliquegraph->noutarcs[i] == 0 )
    11939 {
    11940 sinks[nsinks] = i;
    11941 nsinks++;
    11942 }
    11943 }
    11944
    11945 /* compute for each node a minimum distance to each sources and each sink */
    11946 for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
    11947 {
    11948 int j;
    11949
    11950 for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
    11951 {
    11952 SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
    11953 }
    11954
    11955 for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
    11956 {
    11957 SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
    11958 }
    11959 }
    11960
    11961 (*naddconss) += nconss;
    11962
    11963 /* for the statistic we count the number added variable constraints */
    11964 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
    11965
    11966 SCIPfreeBufferArray(scip, &sinks);
    11967 SCIPfreeBufferArray(scip, &sources);
    11968
    11969 return SCIP_OKAY;
    11970}
    11971
    11972/** initialize the assumed durations for each variable */
    11973static
    11975 SCIP* scip, /**< SCIP data structure */
    11976 TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
    11977 SCIP_CONS** conss, /**< cumulative constraints */
    11978 int nconss /**< number of cumulative constraints */
    11979 )
    11980{
    11981 int c;
    11982
    11983 /* use the cumulative structure to define the duration we are using for each job */
    11984 for( c = 0; c < nconss; ++c )
    11985 {
    11986 SCIP_CONSDATA* consdata;
    11987 SCIP_VAR** vars;
    11988 int nvars;
    11989 int v;
    11990
    11991 consdata = SCIPconsGetData(conss[c]);
    11992 assert(consdata != NULL);
    11993
    11994 vars = consdata->vars;
    11995 nvars = consdata->nvars;
    11996
    11997 for( v = 0; v < nvars; ++v )
    11998 {
    11999 int idx;
    12000
    12001 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
    12002 assert(idx >= 0);
    12003
    12004 /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
    12005 * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
    12006 * general this is not the case. Therefore, the question would be which duration should be used?
    12007 */
    12008 tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
    12009 assert(tcliquegraph->durations[idx] > 0);
    12010 }
    12011 }
    12012
    12013 return SCIP_OKAY;
    12014}
    12015
    12016/** create tclique graph */
    12017static
    12019 SCIP* scip, /**< SCIP data structure */
    12020 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
    12021 )
    12022{
    12023 SCIP_VAR** vars;
    12024 SCIP_HASHMAP* varmap;
    12025 SCIP_Bool** precedencematrix;
    12026 SCIP_Bool** demandmatrix;
    12027 int* ninarcs;
    12028 int* noutarcs;
    12029 int* durations;
    12030 int* weights;
    12031 int nvars;
    12032 int v;
    12033
    12034 vars = SCIPgetVars(scip);
    12035 nvars = SCIPgetNVars(scip);
    12036
    12037 /* allocate memory for the tclique graph data structure */
    12038 SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
    12039
    12040 /* create the variable mapping hash map */
    12041 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
    12042
    12043 /* each active variables get a node in the graph */
    12044 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
    12045
    12046 /* allocate memory for the projected variables bound graph and the none overlapping graph */
    12047 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
    12048 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
    12049
    12050 /* array to buffer the weights of the nodes for the maximum weighted clique computation */
    12051 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
    12052 BMSclearMemoryArray(weights, nvars);
    12053
    12054 /* array to store the number of in arc of the precedence graph */
    12055 SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
    12056 BMSclearMemoryArray(ninarcs, nvars);
    12057
    12058 /* array to store the number of out arc of the precedence graph */
    12059 SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
    12060 BMSclearMemoryArray(noutarcs, nvars);
    12061
    12062 /* array to store the used duration for each node */
    12063 SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
    12064 BMSclearMemoryArray(durations, nvars);
    12065
    12066 for( v = 0; v < nvars; ++v )
    12067 {
    12068 SCIP_VAR* var;
    12069
    12070 var = vars[v];
    12071 assert(var != NULL);
    12072
    12073 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
    12074 BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
    12075
    12076 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
    12077 BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
    12078
    12079 /* insert all active variables into the garph */
    12080 assert(SCIPvarGetProbindex(var) == v);
    12081 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
    12082 }
    12083
    12084 (*tcliquegraph)->nnodes = nvars;
    12085 (*tcliquegraph)->varmap = varmap;
    12086 (*tcliquegraph)->precedencematrix = precedencematrix;
    12087 (*tcliquegraph)->demandmatrix = demandmatrix;
    12088 (*tcliquegraph)->weights = weights;
    12089 (*tcliquegraph)->ninarcs = ninarcs;
    12090 (*tcliquegraph)->noutarcs = noutarcs;
    12091 (*tcliquegraph)->durations = durations;
    12092 (*tcliquegraph)->size = nvars;
    12093
    12094 return SCIP_OKAY;
    12095}
    12096
    12097/** frees the tclique graph */
    12098static
    12100 SCIP* scip, /**< SCIP data structure */
    12101 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
    12102 )
    12103{
    12104 int v;
    12105
    12106 for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
    12107 {
    12108 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
    12109 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
    12110 }
    12111
    12112 SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
    12113 SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
    12114 SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
    12115 SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
    12116 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
    12117 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
    12118 SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
    12119 SCIPhashmapFree(&(*tcliquegraph)->varmap);
    12120
    12121 SCIPfreeBuffer(scip, tcliquegraph);
    12122}
    12123
    12124/** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
    12125 * constrains (disjunctive constraint)
    12126 */
    12127static
    12129 SCIP* scip, /**< SCIP data structure */
    12130 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    12131 SCIP_CONS** conss, /**< array of cumulative constraints */
    12132 int nconss, /**< number of cumulative constraints */
    12133 int* naddconss /**< pointer to store the number of added constraints */
    12134 )
    12135{
    12136 TCLIQUE_GRAPH* tcliquegraph;
    12137
    12138 /* create tclique graph */
    12139 SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
    12140
    12141 /* define for each job a duration */
    12142 SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
    12143
    12144 /* constuct incompatibility graph */
    12145 SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
    12146
    12147 /* search for new precedence constraints */
    12148 if( conshdlrdata->detectvarbounds )
    12149 {
    12150 SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
    12151 }
    12152
    12153 /* search for new cumulative constraints */
    12154 if( conshdlrdata->detectdisjunctive )
    12155 {
    12156 SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
    12157 }
    12158
    12159 /* free tclique graph data structure */
    12160 freeTcliqueGraph(scip, &tcliquegraph);
    12161
    12162 return SCIP_OKAY;
    12163}
    12164
    12165/** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
    12166static
    12168 SCIP_CONSDATA* consdata /**< cumulative constraint data */
    12169 )
    12170{
    12171 SCIP_VAR** vars;
    12172 int nvars;
    12173 int v;
    12174
    12175 if( consdata->validsignature )
    12176 return;
    12177
    12178 vars = consdata->vars;
    12179 nvars = consdata->nvars;
    12180
    12181 for( v = 0; v < nvars; ++v )
    12182 {
    12183 consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
    12184 }
    12185
    12186 consdata->validsignature = TRUE;
    12187}
    12188
    12189/** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
    12190static
    12192{ /*lint --e{715}*/
    12193 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
    12194
    12195 assert(consdata != NULL);
    12196 assert(0 <= ind1 && ind1 < consdata->nvars);
    12197 assert(0 <= ind2 && ind2 < consdata->nvars);
    12198
    12199 return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
    12200}
    12201
    12202/** run a pairwise comparison */
    12203static
    12205 SCIP* scip, /**< SCIP data structure */
    12206 SCIP_CONS** conss, /**< array of cumulative constraints */
    12207 int nconss, /**< number of cumulative constraints */
    12208 int* ndelconss /**< pointer to store the number of deletedconstraints */
    12209 )
    12210{
    12211 int i;
    12212 int j;
    12213
    12214 for( i = 0; i < nconss; ++i )
    12215 {
    12216 SCIP_CONSDATA* consdata0;
    12217 SCIP_CONS* cons0;
    12218
    12219 cons0 = conss[i];
    12220 assert(cons0 != NULL);
    12221
    12222 consdata0 = SCIPconsGetData(cons0);
    12223 assert(consdata0 != NULL);
    12224
    12225 consdataCalcSignature(consdata0);
    12226 assert(consdata0->validsignature);
    12227
    12228 for( j = i+1; j < nconss; ++j )
    12229 {
    12230 SCIP_CONSDATA* consdata1;
    12231 SCIP_CONS* cons1;
    12232
    12233 cons1 = conss[j];
    12234 assert(cons1 != NULL);
    12235
    12236 consdata1 = SCIPconsGetData(cons1);
    12237 assert(consdata1 != NULL);
    12238
    12239 if( consdata0->capacity != consdata1->capacity )
    12240 continue;
    12241
    12242 consdataCalcSignature(consdata1);
    12243 assert(consdata1->validsignature);
    12244
    12245 if( (consdata1->signature & (~consdata0->signature)) == 0 )
    12246 {
    12247 SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
    12248 SCIPswapPointers((void**)&cons0, (void**)&cons1);
    12249 assert((consdata0->signature & (~consdata1->signature)) == 0);
    12250 }
    12251
    12252 if( (consdata0->signature & (~consdata1->signature)) == 0 )
    12253 {
    12254 int* perm0;
    12255 int* perm1;
    12256 int v0;
    12257 int v1;
    12258
    12259 if( consdata0->nvars > consdata1->nvars )
    12260 continue;
    12261
    12262 if( consdata0->hmin < consdata1->hmin )
    12263 continue;
    12264
    12265 if( consdata0->hmax > consdata1->hmax )
    12266 continue;
    12267
    12268 SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
    12269 SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
    12270
    12271 /* call sorting method */
    12272 SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
    12273 SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
    12274
    12275 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
    12276 {
    12277 SCIP_VAR* var0;
    12278 SCIP_VAR* var1;
    12279 int idx0;
    12280 int idx1;
    12281 int comp;
    12282
    12283 idx0 = perm0[v0];
    12284 idx1 = perm1[v1];
    12285
    12286 var0 = consdata0->vars[idx0];
    12287
    12288 var1 = consdata1->vars[idx1];
    12289
    12290 comp = SCIPvarCompare(var0, var1);
    12291
    12292 if( comp == 0 )
    12293 {
    12294 int duration0;
    12295 int duration1;
    12296 int demand0;
    12297 int demand1;
    12298
    12299 demand0 = consdata0->demands[idx0];
    12300 duration0 = consdata0->durations[idx0];
    12301
    12302 demand1 = consdata1->demands[idx1];
    12303 duration1 = consdata1->durations[idx1];
    12304
    12305 if( demand0 != demand1 )
    12306 break;
    12307
    12308 if( duration0 != duration1 )
    12309 break;
    12310
    12311 v0++;
    12312 v1++;
    12313 }
    12314 else if( comp > 0 )
    12315 v1++;
    12316 else
    12317 break;
    12318 }
    12319
    12320 if( v0 == consdata0->nvars )
    12321 {
    12322 if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
    12323 {
    12324 initializeLocks(consdata1, TRUE);
    12325 }
    12326
    12327 /* coverity[swapped_arguments] */
    12328 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
    12329
    12330 SCIP_CALL( SCIPdelCons(scip, cons0) );
    12331 (*ndelconss)++;
    12332 }
    12333
    12334 SCIPfreeBufferArray(scip, &perm1);
    12335 SCIPfreeBufferArray(scip, &perm0);
    12336 }
    12337 }
    12338 }
    12339
    12340 return SCIP_OKAY;
    12341}
    12342
    12343/** strengthen the variable bounds using the cumulative condition */
    12344static
    12346 SCIP* scip, /**< SCIP data structure */
    12347 SCIP_CONS* cons, /**< constraint to propagate */
    12348 int* nchgbds, /**< pointer to store the number of changed bounds */
    12349 int* naddconss /**< pointer to store the number of added constraints */
    12350 )
    12351{
    12352 SCIP_CONSDATA* consdata;
    12353 SCIP_VAR** vars;
    12354 int* durations;
    12355 int* demands;
    12356 int capacity;
    12357 int nvars;
    12358 int nconss;
    12359 int i;
    12360
    12361 consdata = SCIPconsGetData(cons);
    12362 assert(consdata != NULL);
    12363
    12364 /* check if the variable bounds got already strengthen by the cumulative constraint */
    12365 if( consdata->varbounds )
    12366 return SCIP_OKAY;
    12367
    12368 vars = consdata->vars;
    12369 durations = consdata->durations;
    12370 demands = consdata->demands;
    12371 capacity = consdata->capacity;
    12372 nvars = consdata->nvars;
    12373
    12374 nconss = 0;
    12375
    12376 for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
    12377 {
    12378 SCIP_VAR** vbdvars;
    12379 SCIP_VAR* var;
    12380 SCIP_Real* vbdcoefs;
    12381 SCIP_Real* vbdconsts;
    12382 int nvbdvars;
    12383 int b;
    12384 int j;
    12385
    12386 var = consdata->vars[i];
    12387 assert(var != NULL);
    12388
    12389 vbdvars = SCIPvarGetVlbVars(var);
    12390 vbdcoefs = SCIPvarGetVlbCoefs(var);
    12391 vbdconsts = SCIPvarGetVlbConstants(var);
    12392 nvbdvars = SCIPvarGetNVlbs(var);
    12393
    12394 for( b = 0; b < nvbdvars; ++b )
    12395 {
    12396 if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
    12397 {
    12398 if( boundedConvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
    12399 {
    12400 for( j = 0; j < nvars; ++j )
    12401 {
    12402 if( vars[j] == vbdvars[b] )
    12403 break;
    12404 }
    12405 if( j == nvars )
    12406 continue;
    12407
    12408 if( demands[i] + demands[j] > capacity &&
    12409 boundedConvertRealToInt(scip, vbdconsts[b]) < durations[j] )
    12410 {
    12411 SCIP_Bool infeasible;
    12412 char name[SCIP_MAXSTRLEN];
    12413 int nlocalbdchgs;
    12414
    12415 SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
    12416
    12417 /* construct constraint name */
    12418 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
    12419
    12420 SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
    12421 nconss++;
    12422
    12423 SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
    12424 assert(!infeasible);
    12425
    12426 (*nchgbds) += nlocalbdchgs;
    12427 }
    12428 }
    12429 }
    12430 }
    12431 }
    12432
    12433 (*naddconss) += nconss;
    12434
    12435 consdata->varbounds = TRUE;
    12436
    12437 return SCIP_OKAY;
    12438}
    12439
    12440/** helper function to enforce constraints */
    12441static
    12443 SCIP* scip, /**< SCIP data structure */
    12444 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    12445 SCIP_CONS** conss, /**< constraints to process */
    12446 int nconss, /**< number of constraints */
    12447 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
    12448 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    12449 SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
    12450 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    12451 )
    12452{
    12453 SCIP_CONSHDLRDATA* conshdlrdata;
    12454
    12455 assert(conshdlr != NULL);
    12456 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12457 assert(nconss == 0 || conss != NULL);
    12458 assert(result != NULL);
    12459
    12460 if( solinfeasible )
    12461 {
    12462 *result = SCIP_INFEASIBLE;
    12463 return SCIP_OKAY;
    12464 }
    12465
    12466 SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
    12467 sol == NULL ? "LP" : "relaxation");
    12468
    12469 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12470 assert(conshdlrdata != NULL);
    12471
    12472 (*result) = SCIP_FEASIBLE;
    12473
    12474 if( conshdlrdata->usebinvars )
    12475 {
    12476 SCIP_Bool separated;
    12477 SCIP_Bool cutoff;
    12478 int c;
    12479
    12480 separated = FALSE;
    12481
    12482 /* first check if a constraints is violated */
    12483 for( c = 0; c < nusefulconss; ++c )
    12484 {
    12485 SCIP_CONS* cons;
    12486 SCIP_Bool violated;
    12487
    12488 cons = conss[c];
    12489 assert(cons != NULL);
    12490
    12491 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
    12492
    12493 if( !violated )
    12494 continue;
    12495
    12496 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
    12497 if ( cutoff )
    12498 {
    12499 *result = SCIP_CUTOFF;
    12500 return SCIP_OKAY;
    12501 }
    12502 }
    12503
    12504 for( ; c < nconss && !separated; ++c )
    12505 {
    12506 SCIP_CONS* cons;
    12507 SCIP_Bool violated;
    12508
    12509 cons = conss[c];
    12510 assert(cons != NULL);
    12511
    12512 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
    12513
    12514 if( !violated )
    12515 continue;
    12516
    12517 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
    12518 if ( cutoff )
    12519 {
    12520 *result = SCIP_CUTOFF;
    12521 return SCIP_OKAY;
    12522 }
    12523 }
    12524
    12525 if( separated )
    12526 (*result) = SCIP_SEPARATED;
    12527 }
    12528 else
    12529 {
    12530 SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
    12531 }
    12532
    12533 return SCIP_OKAY;
    12534}
    12535
    12536/**@} */
    12537
    12538
    12539/**@name Callback methods of constraint handler
    12540 *
    12541 * @{
    12542 */
    12543
    12544/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    12545static
    12546SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
    12547{ /*lint --e{715}*/
    12548 assert(scip != NULL);
    12549 assert(conshdlr != NULL);
    12550 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12551
    12552 /* call inclusion method of constraint handler */
    12554
    12556
    12557 *valid = TRUE;
    12558
    12559 return SCIP_OKAY;
    12560}
    12561
    12562/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    12563static
    12564SCIP_DECL_CONSFREE(consFreeCumulative)
    12565{ /*lint --e{715}*/
    12566 SCIP_CONSHDLRDATA* conshdlrdata;
    12567
    12568 assert(conshdlr != NULL);
    12569 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12570
    12571 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12572 assert(conshdlrdata != NULL);
    12573
    12574#ifdef SCIP_STATISTIC
    12575 if( !conshdlrdata->iscopy )
    12576 {
    12577 /* statisitc output if SCIP_STATISTIC is defined */
    12578 SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
    12579 conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
    12580 SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
    12581 conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
    12582 SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
    12583 conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
    12584 }
    12585#endif
    12586
    12587 conshdlrdataFree(scip, &conshdlrdata);
    12588
    12589 SCIPconshdlrSetData(conshdlr, NULL);
    12590
    12591 return SCIP_OKAY;
    12592}
    12593
    12594
    12595/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    12596static
    12597SCIP_DECL_CONSINITPRE(consInitpreCumulative)
    12598{ /*lint --e{715}*/
    12599 SCIP_CONSHDLRDATA* conshdlrdata;
    12600 int c;
    12601
    12602 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12603 assert(conshdlrdata != NULL);
    12604
    12605 conshdlrdata->detectedredundant = FALSE;
    12606
    12607 for( c = 0; c < nconss; ++c )
    12608 {
    12609 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
    12610 * hmax)
    12611 */
    12612 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
    12613 }
    12614
    12615 return SCIP_OKAY;
    12616}
    12617
    12618
    12619/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
    12620#ifdef SCIP_STATISTIC
    12621static
    12622SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
    12623{ /*lint --e{715}*/
    12624 SCIP_CONSHDLRDATA* conshdlrdata;
    12625 int c;
    12626
    12627 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12628 assert(conshdlrdata != NULL);
    12629
    12630 for( c = 0; c < nconss; ++c )
    12631 {
    12632 SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
    12633
    12634#ifdef SCIP_DISABLED_CODE
    12636#endif
    12637 }
    12638
    12639 if( !conshdlrdata->iscopy )
    12640 {
    12641 SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
    12642 SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
    12643 SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
    12644 SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
    12645 SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
    12646 SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
    12647 SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
    12648 SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
    12649 SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
    12650 }
    12651
    12652 return SCIP_OKAY;
    12653}
    12654#endif
    12655
    12656
    12657/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    12658static
    12659SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
    12660{ /*lint --e{715}*/
    12661 SCIP_CONSDATA* consdata;
    12662 int c;
    12663
    12664 assert(conshdlr != NULL);
    12665 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12666
    12667 /* release the rows of all constraints */
    12668 for( c = 0; c < nconss; ++c )
    12669 {
    12670 consdata = SCIPconsGetData(conss[c]);
    12671 assert(consdata != NULL);
    12672
    12673 /* free rows */
    12674 SCIP_CALL( consdataFreeRows(scip, &consdata) );
    12675 }
    12676
    12677 return SCIP_OKAY;
    12678}
    12679
    12680/** frees specific constraint data */
    12681static
    12682SCIP_DECL_CONSDELETE(consDeleteCumulative)
    12683{ /*lint --e{715}*/
    12684 assert(conshdlr != NULL);
    12685 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12686 assert(consdata != NULL );
    12687 assert(*consdata != NULL );
    12688
    12689 /* if constraint belongs to transformed problem space, drop bound change events on variables */
    12690 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
    12691 {
    12692 SCIP_CONSHDLRDATA* conshdlrdata;
    12693
    12694 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12695 assert(conshdlrdata != NULL);
    12696
    12697 SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
    12698 }
    12699
    12700 /* free cumulative constraint data */
    12701 SCIP_CALL( consdataFree(scip, consdata) );
    12702
    12703 return SCIP_OKAY;
    12704}
    12705
    12706/** transforms constraint data into data belonging to the transformed problem */
    12707static
    12708SCIP_DECL_CONSTRANS(consTransCumulative)
    12709{ /*lint --e{715}*/
    12710 SCIP_CONSHDLRDATA* conshdlrdata;
    12711 SCIP_CONSDATA* sourcedata;
    12712 SCIP_CONSDATA* targetdata;
    12713
    12714 assert(conshdlr != NULL);
    12716 assert(sourcecons != NULL);
    12717 assert(targetcons != NULL);
    12718
    12719 sourcedata = SCIPconsGetData(sourcecons);
    12720 assert(sourcedata != NULL);
    12721 assert(sourcedata->demandrows == NULL);
    12722
    12723 SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
    12724
    12725 /* get event handler */
    12726 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12727 assert(conshdlrdata != NULL);
    12728 assert(conshdlrdata->eventhdlr != NULL);
    12729
    12730 /* create constraint data for target constraint */
    12731 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
    12732 sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
    12733 sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
    12734
    12735 /* create target constraint */
    12736 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
    12737 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
    12738 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
    12739 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
    12740 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
    12741
    12742 /* catch bound change events of variables */
    12743 SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
    12744
    12745 return SCIP_OKAY;
    12746}
    12747
    12748/** LP initialization method of constraint handler */
    12749static
    12750SCIP_DECL_CONSINITLP(consInitlpCumulative)
    12751{
    12752 SCIP_CONSHDLRDATA* conshdlrdata;
    12753 int c;
    12754
    12755 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12756 assert(conshdlr != NULL);
    12757 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12758 assert(conshdlrdata != NULL);
    12759
    12760 *infeasible = FALSE;
    12761
    12762 SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
    12763
    12764 if( conshdlrdata->usebinvars )
    12765 {
    12766 /* add rows to LP */
    12767 for( c = 0; c < nconss && !(*infeasible); ++c )
    12768 {
    12769 assert(SCIPconsIsInitial(conss[c]));
    12770 SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
    12771
    12772 if( conshdlrdata->cutsasconss )
    12773 {
    12775 }
    12776 }
    12777 }
    12778
    12779 /**@todo if we want to use only the integer variables; only these will be in cuts
    12780 * create some initial cuts, currently these are only separated */
    12781
    12782 return SCIP_OKAY;
    12783}
    12784
    12785/** separation method of constraint handler for LP solutions */
    12786static
    12787SCIP_DECL_CONSSEPALP(consSepalpCumulative)
    12788{
    12789 SCIP_CONSHDLRDATA* conshdlrdata;
    12790 SCIP_Bool cutoff;
    12791 SCIP_Bool separated;
    12792 int c;
    12793
    12794 SCIPdebugMsg(scip, "consSepalpCumulative\n");
    12795
    12796 assert(conshdlr != NULL);
    12797 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12798 assert(nconss == 0 || conss != NULL);
    12799 assert(result != NULL);
    12800 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12801 assert(conshdlrdata != NULL);
    12802
    12803 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
    12804
    12805 cutoff = FALSE;
    12806 separated = FALSE;
    12807 (*result) = SCIP_DIDNOTRUN;
    12808
    12809 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
    12810 return SCIP_OKAY;
    12811
    12812 (*result) = SCIP_DIDNOTFIND;
    12813
    12814 if( conshdlrdata->usebinvars )
    12815 {
    12816 /* check all useful cumulative constraints for feasibility */
    12817 for( c = 0; c < nusefulconss && !cutoff; ++c )
    12818 {
    12819 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
    12820 }
    12821
    12822 if( !cutoff && conshdlrdata->usecovercuts )
    12823 {
    12824 for( c = 0; c < nusefulconss; ++c )
    12825 {
    12826 SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
    12827 }
    12828 }
    12829 }
    12830
    12831 if( conshdlrdata->sepaold )
    12832 {
    12833 /* separate cuts containing only integer variables */
    12834 for( c = 0; c < nusefulconss; ++c )
    12835 {
    12836 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
    12837 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
    12838 }
    12839 }
    12840
    12841 if( cutoff )
    12842 *result = SCIP_CUTOFF;
    12843 else if( separated )
    12844 *result = SCIP_SEPARATED;
    12845
    12846 return SCIP_OKAY;
    12847}
    12848
    12849/** separation method of constraint handler for arbitrary primal solutions */
    12850static
    12851SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
    12852{ /*lint --e{715}*/
    12853 SCIP_CONSHDLRDATA* conshdlrdata;
    12854 SCIP_Bool cutoff;
    12855 SCIP_Bool separated;
    12856 int c;
    12857
    12858 assert(conshdlr != NULL);
    12859 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12860 assert(nconss == 0 || conss != NULL);
    12861 assert(result != NULL);
    12862
    12863 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12864 assert(conshdlrdata != NULL);
    12865
    12866 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
    12867 return SCIP_OKAY;
    12868
    12869 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
    12870
    12871 cutoff = FALSE;
    12872 separated = FALSE;
    12873 (*result) = SCIP_DIDNOTFIND;
    12874
    12875 if( conshdlrdata->usebinvars )
    12876 {
    12877 /* check all useful cumulative constraints for feasibility */
    12878 for( c = 0; c < nusefulconss && !cutoff; ++c )
    12879 {
    12880 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
    12881 }
    12882
    12883 if( !cutoff && conshdlrdata->usecovercuts )
    12884 {
    12885 for( c = 0; c < nusefulconss; ++c )
    12886 {
    12887 SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
    12888 }
    12889 }
    12890 }
    12891 if( conshdlrdata->sepaold )
    12892 {
    12893 /* separate cuts containing only integer variables */
    12894 for( c = 0; c < nusefulconss; ++c )
    12895 {
    12896 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
    12897 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
    12898 }
    12899 }
    12900
    12901 if( cutoff )
    12902 *result = SCIP_CUTOFF;
    12903 else if( separated )
    12904 *result = SCIP_SEPARATED;
    12905
    12906 return SCIP_OKAY;
    12907}
    12908
    12909/** constraint enforcing method of constraint handler for LP solutions */
    12910static
    12911SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
    12912{ /*lint --e{715}*/
    12913 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
    12914
    12915 return SCIP_OKAY;
    12916}
    12917
    12918/** constraint enforcing method of constraint handler for relaxation solutions */
    12919static
    12920SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
    12921{ /*lint --e{715}*/
    12922 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
    12923
    12924 return SCIP_OKAY;
    12925}
    12926
    12927/** constraint enforcing method of constraint handler for pseudo solutions */
    12928static
    12929SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
    12930{ /*lint --e{715}*/
    12931 SCIP_CONSHDLRDATA* conshdlrdata;
    12932
    12933 SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
    12934
    12935 assert(conshdlr != NULL);
    12936 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12937 assert(nconss == 0 || conss != NULL);
    12938 assert(result != NULL);
    12939
    12940 if( objinfeasible )
    12941 {
    12942 *result = SCIP_DIDNOTRUN;
    12943 return SCIP_OKAY;
    12944 }
    12945
    12946 (*result) = SCIP_FEASIBLE;
    12947
    12948 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12949 assert(conshdlrdata != NULL);
    12950
    12951 SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
    12952
    12953 return SCIP_OKAY;
    12954}
    12955
    12956/** feasibility check method of constraint handler for integral solutions */
    12957static
    12958SCIP_DECL_CONSCHECK(consCheckCumulative)
    12959{ /*lint --e{715}*/
    12960 int c;
    12961
    12962 assert(conshdlr != NULL);
    12963 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12964 assert(nconss == 0 || conss != NULL);
    12965 assert(result != NULL);
    12966
    12967 *result = SCIP_FEASIBLE;
    12968
    12969 SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
    12970
    12971 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
    12972 {
    12973 SCIP_Bool violated = FALSE;
    12974
    12975 SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
    12976
    12977 if( violated )
    12978 *result = SCIP_INFEASIBLE;
    12979 }
    12980
    12981 return SCIP_OKAY;
    12982}
    12983
    12984/** domain propagation method of constraint handler */
    12985static
    12986SCIP_DECL_CONSPROP(consPropCumulative)
    12987{ /*lint --e{715}*/
    12988 SCIP_CONSHDLRDATA* conshdlrdata;
    12989 SCIP_Bool cutoff;
    12990 int nchgbds;
    12991 int ndelconss;
    12992 int c;
    12993
    12994 SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
    12995
    12996 assert(conshdlr != NULL);
    12997 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12998 assert(nconss == 0 || conss != NULL);
    12999 assert(result != NULL);
    13000
    13001 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13002 assert(conshdlrdata != NULL);
    13003
    13004 nchgbds = 0;
    13005 ndelconss = 0;
    13006 cutoff = FALSE;
    13007 (*result) = SCIP_DIDNOTRUN;
    13008
    13009 /* propgate all useful constraints */
    13010 for( c = 0; c < nusefulconss && !cutoff; ++c )
    13011 {
    13012 SCIP_CONS* cons;
    13013
    13014 cons = conss[c];
    13015 assert(cons != NULL);
    13016
    13017 if( SCIPgetDepth(scip) == 0 )
    13018 {
    13020 &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
    13021
    13022 if( cutoff )
    13023 break;
    13024
    13025 if( SCIPconsIsDeleted(cons) )
    13026 continue;
    13027 }
    13028
    13029 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
    13030 }
    13031
    13032 if( !cutoff && nchgbds == 0 )
    13033 {
    13034 /* propgate all other constraints */
    13035 for( c = nusefulconss; c < nconss && !cutoff; ++c )
    13036 {
    13037 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
    13038 }
    13039 }
    13040
    13041 if( cutoff )
    13042 {
    13043 SCIPdebugMsg(scip, "detected infeasible\n");
    13044 *result = SCIP_CUTOFF;
    13045 }
    13046 else if( nchgbds > 0 )
    13047 {
    13048 SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
    13049 *result = SCIP_REDUCEDDOM;
    13050 }
    13051 else
    13052 *result = SCIP_DIDNOTFIND;
    13053
    13054 return SCIP_OKAY;
    13055}
    13056
    13057/** presolving method of constraint handler */
    13058static
    13059SCIP_DECL_CONSPRESOL(consPresolCumulative)
    13060{ /*lint --e{715}*/
    13061 SCIP_CONSHDLRDATA* conshdlrdata;
    13062 SCIP_CONS* cons;
    13063 SCIP_Bool cutoff;
    13064 SCIP_Bool unbounded;
    13065 int oldnfixedvars;
    13066 int oldnchgbds;
    13067 int oldndelconss;
    13068 int oldnaddconss;
    13069 int oldnupgdconss;
    13070 int oldnchgsides;
    13071 int oldnchgcoefs;
    13072 int c;
    13073
    13074 assert(conshdlr != NULL);
    13075 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    13076 assert(scip != NULL);
    13077 assert(result != NULL);
    13078
    13079 SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
    13080
    13081 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13082 assert(conshdlrdata != NULL);
    13083
    13084 *result = SCIP_DIDNOTRUN;
    13085
    13086 oldnfixedvars = *nfixedvars;
    13087 oldnchgbds = *nchgbds;
    13088 oldnchgsides = *nchgsides;
    13089 oldnchgcoefs = *nchgcoefs;
    13090 oldnupgdconss = *nupgdconss;
    13091 oldndelconss = *ndelconss;
    13092 oldnaddconss = *naddconss;
    13093 cutoff = FALSE;
    13094 unbounded = FALSE;
    13095
    13096 /* process constraints */
    13097 for( c = 0; c < nconss && !cutoff; ++c )
    13098 {
    13099 cons = conss[c];
    13100
    13101 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
    13102 * hmax)
    13103 */
    13104 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
    13105
    13106 if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
    13107 {
    13108 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
    13109 nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
    13110
    13111 if( cutoff || unbounded )
    13112 break;
    13113
    13114 if( SCIPconsIsDeleted(cons) )
    13115 continue;
    13116 }
    13117
    13118 /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
    13119 if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
    13120 {
    13121 SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
    13122 }
    13123
    13124 /* strengthen existing variable bounds using the cumulative condition */
    13125 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    13126 {
    13127 SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
    13128 }
    13129
    13130 /* propagate cumulative constraint */
    13131 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
    13132 assert(checkDemands(scip, cons) || cutoff);
    13133 }
    13134
    13135 if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    13136 {
    13137 SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
    13138 }
    13139
    13140 /* only perform the detection of variable bounds and disjunctive constraint once */
    13141 if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
    13142 && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
    13143 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    13144 {
    13145 /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
    13146 * propagation
    13147 */
    13148 SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
    13149 conshdlrdata->detectedredundant = TRUE;
    13150 }
    13151
    13152 if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    13153 {
    13154 SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
    13155 }
    13156
    13157 SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
    13158 *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
    13159
    13160 if( cutoff )
    13161 *result = SCIP_CUTOFF;
    13162 else if( unbounded )
    13163 *result = SCIP_UNBOUNDED;
    13164 else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
    13165 || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
    13166 *result = SCIP_SUCCESS;
    13167 else
    13168 *result = SCIP_DIDNOTFIND;
    13169
    13170 return SCIP_OKAY;
    13171}
    13172
    13173/** propagation conflict resolving method of constraint handler */
    13174static
    13175SCIP_DECL_CONSRESPROP(consRespropCumulative)
    13176{ /*lint --e{715}*/
    13177 SCIP_CONSHDLRDATA* conshdlrdata;
    13178 SCIP_CONSDATA* consdata;
    13179
    13180 assert(conshdlr != NULL);
    13181 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    13182 assert(scip != NULL);
    13183 assert(result != NULL);
    13184 assert(infervar != NULL);
    13185 assert(bdchgidx != NULL);
    13186
    13187 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13188 assert(conshdlrdata != NULL);
    13189
    13190 /* process constraint */
    13191 assert(cons != NULL);
    13192
    13193 consdata = SCIPconsGetData(cons);
    13194 assert(consdata != NULL);
    13195
    13196 SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
    13197 SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
    13199
    13200 SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
    13201 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
    13202 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
    13203
    13204 return SCIP_OKAY;
    13205}
    13206
    13207/** variable rounding lock method of constraint handler */
    13208static
    13209SCIP_DECL_CONSLOCK(consLockCumulative)
    13210{ /*lint --e{715}*/
    13211 SCIP_CONSDATA* consdata;
    13212 SCIP_VAR** vars;
    13213 int v;
    13214
    13215 SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
    13216
    13217 assert(scip != NULL);
    13218 assert(cons != NULL);
    13219 assert(locktype == SCIP_LOCKTYPE_MODEL);
    13220
    13221 consdata = SCIPconsGetData(cons);
    13222 assert(consdata != NULL);
    13223
    13224 vars = consdata->vars;
    13225 assert(vars != NULL);
    13226
    13227 for( v = 0; v < consdata->nvars; ++v )
    13228 {
    13229 if( consdata->downlocks[v] && consdata->uplocks[v] )
    13230 {
    13231 /* the integer start variable should not get rounded in both direction */
    13232 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
    13233 }
    13234 else if( consdata->downlocks[v] )
    13235 {
    13236 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
    13237 }
    13238 else if( consdata->uplocks[v] )
    13239 {
    13240 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
    13241 }
    13242 }
    13243
    13244 return SCIP_OKAY;
    13245}
    13246
    13247
    13248/** constraint display method of constraint handler */
    13249static
    13250SCIP_DECL_CONSPRINT(consPrintCumulative)
    13251{ /*lint --e{715}*/
    13252 assert(scip != NULL);
    13253 assert(conshdlr != NULL);
    13254 assert(cons != NULL);
    13255
    13256 consdataPrint(scip, SCIPconsGetData(cons), file);
    13257
    13258 return SCIP_OKAY;
    13259}
    13260
    13261/** constraint copying method of constraint handler */
    13262static
    13263SCIP_DECL_CONSCOPY(consCopyCumulative)
    13264{ /*lint --e{715}*/
    13265 SCIP_CONSDATA* sourceconsdata;
    13266 SCIP_VAR** sourcevars;
    13267 SCIP_VAR** vars;
    13268 const char* consname;
    13269
    13270 int nvars;
    13271 int v;
    13272
    13273 sourceconsdata = SCIPconsGetData(sourcecons);
    13274 assert(sourceconsdata != NULL);
    13275
    13276 /* get variables of the source constraint */
    13277 nvars = sourceconsdata->nvars;
    13278 sourcevars = sourceconsdata->vars;
    13279
    13280 (*valid) = TRUE;
    13281
    13282 if( nvars == 0 )
    13283 return SCIP_OKAY;
    13284
    13285 /* allocate buffer array */
    13286 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
    13287
    13288 for( v = 0; v < nvars && *valid; ++v )
    13289 {
    13290 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
    13291 assert(!(*valid) || vars[v] != NULL);
    13292 }
    13293
    13294 /* only create the target constraint, if all variables could be copied */
    13295 if( *valid )
    13296 {
    13297 if( name != NULL )
    13298 consname = name;
    13299 else
    13300 consname = SCIPconsGetName(sourcecons);
    13301
    13302 /* create a copy of the cumulative constraint */
    13303 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
    13304 sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
    13305 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    13306
    13307 /* adjust left side if the time axis if needed */
    13308 if( sourceconsdata->hmin > 0 )
    13309 {
    13310 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
    13311 }
    13312
    13313 /* adjust right side if the time axis if needed */
    13314 if( sourceconsdata->hmax < INT_MAX )
    13315 {
    13316 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
    13317 }
    13318 }
    13319
    13320 /* free buffer array */
    13321 SCIPfreeBufferArray(scip, &vars);
    13322
    13323 return SCIP_OKAY;
    13324}
    13325
    13326
    13327/** constraint parsing method of constraint handler */
    13328static
    13329SCIP_DECL_CONSPARSE(consParseCumulative)
    13330{ /*lint --e{715}*/
    13331 SCIP_VAR** vars;
    13332 SCIP_VAR* var;
    13333 SCIP_Real value;
    13334 char strvalue[SCIP_MAXSTRLEN];
    13335 char* endptr;
    13336 int* demands;
    13337 int* durations;
    13338 int capacity;
    13339 int duration;
    13340 int demand;
    13341 int hmin;
    13342 int hmax;
    13343 int varssize;
    13344 int nvars;
    13345
    13346 SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
    13347
    13348 *success = TRUE;
    13349
    13350 /* cutoff "cumulative" form the constraint string */
    13351 SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
    13352 str = endptr;
    13353
    13354 varssize = 100;
    13355 nvars = 0;
    13356
    13357 /* allocate buffer array for variables */
    13358 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
    13359 SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
    13360 SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
    13361
    13362 do
    13363 {
    13364 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
    13365
    13366 if( var == NULL )
    13367 {
    13368 endptr = strchr(endptr, ')');
    13369
    13370 if( endptr == NULL )
    13371 *success = FALSE;
    13372 else
    13373 str = endptr;
    13374
    13375 break;
    13376 }
    13377
    13378 str = endptr;
    13379 SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
    13380 duration = atoi(strvalue);
    13381 str = endptr;
    13382
    13383 SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
    13384 demand = atoi(strvalue);
    13385 str = endptr;
    13386
    13387 SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
    13388
    13389 vars[nvars] = var;
    13390 demands[nvars] = demand;
    13391 durations[nvars] = duration;
    13392 nvars++;
    13393 }
    13394 while( *str != ')' );
    13395
    13396 if( *success )
    13397 {
    13398 /* parse effective time window */
    13399 SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
    13400 hmin = atoi(strvalue);
    13401 str = endptr;
    13402
    13403 if( SCIPparseReal(scip, str, &value, &endptr) )
    13404 {
    13405 hmax = boundedConvertRealToInt(scip, value);
    13406 str = endptr;
    13407
    13408 /* parse capacity */
    13409 SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
    13410 str = endptr;
    13411 if( SCIPparseReal(scip, str, &value, &endptr) )
    13412 {
    13413 capacity = (int)value;
    13414
    13415 /* create cumulative constraint */
    13416 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
    13417 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    13418
    13419 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
    13420 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
    13421 }
    13422 }
    13423 }
    13424
    13425 /* free buffer arrays */
    13426 SCIPfreeBufferArray(scip, &durations);
    13427 SCIPfreeBufferArray(scip, &demands);
    13428 SCIPfreeBufferArray(scip, &vars);
    13429
    13430 return SCIP_OKAY;
    13431}
    13432
    13433
    13434/** constraint method of constraint handler which returns the variables (if possible) */
    13435static
    13436SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
    13437{ /*lint --e{715}*/
    13438 SCIP_CONSDATA* consdata;
    13439
    13440 consdata = SCIPconsGetData(cons);
    13441 assert(consdata != NULL);
    13442
    13443 if( varssize < consdata->nvars )
    13444 (*success) = FALSE;
    13445 else
    13446 {
    13447 assert(vars != NULL);
    13448
    13449 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
    13450 (*success) = TRUE;
    13451 }
    13452
    13453 return SCIP_OKAY;
    13454}
    13455
    13456/** constraint method of constraint handler which returns the number of variables (if possible) */
    13457static
    13458SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
    13459{ /*lint --e{715}*/
    13460 SCIP_CONSDATA* consdata;
    13461
    13462 consdata = SCIPconsGetData(cons);
    13463 assert(consdata != NULL);
    13464
    13465 (*nvars) = consdata->nvars;
    13466 (*success) = TRUE;
    13467
    13468 return SCIP_OKAY;
    13469}
    13470
    13471/**@} */
    13472
    13473/**@name Callback methods of event handler
    13474 *
    13475 * @{
    13476 */
    13477
    13478
    13479/** execution method of event handler */
    13480static
    13481SCIP_DECL_EVENTEXEC(eventExecCumulative)
    13482{ /*lint --e{715}*/
    13483 SCIP_CONSDATA* consdata;
    13484
    13485 assert(scip != NULL);
    13486 assert(eventhdlr != NULL);
    13487 assert(eventdata != NULL);
    13488 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
    13489 assert(event != NULL);
    13490
    13491 consdata = (SCIP_CONSDATA*)eventdata;
    13492 assert(consdata != NULL);
    13493
    13494 /* mark the constraint to be not propagated */
    13495 consdata->propagated = FALSE;
    13496
    13497 return SCIP_OKAY;
    13498}
    13499
    13500/**@} */
    13501
    13502/*
    13503 * constraint specific interface methods
    13504 */
    13505
    13506/** creates the handler for cumulative constraints and includes it in SCIP */
    13508 SCIP* scip /**< SCIP data structure */
    13509 )
    13510{
    13511 SCIP_CONSHDLRDATA* conshdlrdata;
    13512 SCIP_CONSHDLR* conshdlr;
    13513 SCIP_EVENTHDLR* eventhdlr;
    13514
    13515 /* create event handler for bound change events */
    13516 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
    13517
    13518 /* create cumulative constraint handler data */
    13519 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
    13520
    13521 /* include constraint handler */
    13524 consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
    13525 conshdlrdata) );
    13526
    13527 assert(conshdlr != NULL);
    13528
    13529 /* set non-fundamental callbacks via specific setter functions */
    13530 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
    13531 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
    13532#ifdef SCIP_STATISTIC
    13533 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
    13534#endif
    13535 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
    13536 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
    13537 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
    13538 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
    13539 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
    13540 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
    13541 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
    13542 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
    13544 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
    13547 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
    13548 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
    13550 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
    13551 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
    13552
    13553 /* add cumulative constraint handler parameters */
    13555 "constraints/" CONSHDLR_NAME "/maxtime", "maximum range for time horizon",
    13556 &conshdlrdata->maxtime, TRUE, DEFAULT_MAXTIME, 0, INT_MAX, NULL, NULL) );
    13558 "constraints/" CONSHDLR_NAME "/ttinfer",
    13559 "should time-table (core-times) propagator be used to infer bounds?",
    13560 &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
    13562 "constraints/" CONSHDLR_NAME "/efcheck",
    13563 "should edge-finding be used to detect an overload?",
    13564 &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
    13566 "constraints/" CONSHDLR_NAME "/efinfer",
    13567 "should edge-finding be used to infer bounds?",
    13568 &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
    13570 "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
    13571 &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
    13573 "constraints/" CONSHDLR_NAME "/ttefcheck",
    13574 "should time-table edge-finding be used to detect an overload?",
    13575 &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
    13577 "constraints/" CONSHDLR_NAME "/ttefinfer",
    13578 "should time-table edge-finding be used to infer bounds?",
    13579 &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
    13580
    13582 "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
    13583 &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
    13585 "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
    13586 &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
    13588 "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
    13589 &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
    13591 "constraints/" CONSHDLR_NAME "/cutsasconss",
    13592 "should the cumulative constraint create cuts as knapsack constraints?",
    13593 &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
    13595 "constraints/" CONSHDLR_NAME "/sepaold",
    13596 "shall old sepa algo be applied?",
    13597 &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
    13598
    13600 "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
    13601 &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
    13602
    13603 /* presolving parameters */
    13605 "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
    13606 &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
    13608 "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
    13609 &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
    13611 "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
    13612 &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
    13614 "constraints/" CONSHDLR_NAME "/presolpairwise",
    13615 "should pairwise constraint comparison be performed in presolving?",
    13616 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
    13618 "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
    13619 &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
    13620
    13622 "constraints/" CONSHDLR_NAME "/maxnodes",
    13623 "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
    13624 &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
    13626 "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
    13627 &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
    13629 "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
    13630 &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
    13631
    13632 /* conflict analysis parameters */
    13634 "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
    13635 &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
    13636
    13637 return SCIP_OKAY;
    13638}
    13639
    13640/** creates and captures a cumulative constraint */
    13642 SCIP* scip, /**< SCIP data structure */
    13643 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13644 const char* name, /**< name of constraint */
    13645 int nvars, /**< number of variables (jobs) */
    13646 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    13647 int* durations, /**< array containing corresponding durations */
    13648 int* demands, /**< array containing corresponding demands */
    13649 int capacity, /**< available cumulative capacity */
    13650 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    13651 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    13652 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    13653 * Usually set to TRUE. */
    13654 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    13655 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    13656 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    13657 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    13658 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    13659 * Usually set to TRUE. */
    13660 SCIP_Bool local, /**< is constraint only valid locally?
    13661 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    13662 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    13663 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    13664 * adds coefficients to this constraint. */
    13665 SCIP_Bool dynamic, /**< is constraint subject to aging?
    13666 * Usually set to FALSE. Set to TRUE for own cuts which
    13667 * are seperated as constraints. */
    13668 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    13669 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    13670 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    13671 * if it may be moved to a more global node?
    13672 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    13673 )
    13674{
    13675 int i;
    13676 SCIP_CONSHDLR* conshdlr;
    13677 SCIP_CONSDATA* consdata;
    13678
    13679 assert(scip != NULL);
    13680
    13681 /* find the cumulative constraint handler */
    13682 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    13683 if( conshdlr == NULL )
    13684 {
    13685 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
    13686 return SCIP_PLUGINNOTFOUND;
    13687 }
    13688
    13689 for( i = 0; i < nvars; ++i )
    13690 {
    13691 if( INT_MAX - durations[i] < boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(vars[i])) )
    13692 {
    13693 SCIPerrorMessage("detected potential integer overflow for variable <%s> in constraint <%s>: "
    13694 "decrease upper bound of variable or time horizon constraints/" CONSHDLR_NAME "/maxtime\n",
    13695 name, SCIPvarGetName(vars[i]));
    13696 return SCIP_INVALIDDATA;
    13697 }
    13698 }
    13699 SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
    13700
    13701 /* create constraint data */
    13702 SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
    13703
    13704 /* create constraint */
    13705 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
    13706 initial, separate, enforce, check, propagate,
    13707 local, modifiable, dynamic, removable, stickingatnode) );
    13708
    13710 {
    13711 SCIP_CONSHDLRDATA* conshdlrdata;
    13712
    13713 /* get event handler */
    13714 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13715 assert(conshdlrdata != NULL);
    13716 assert(conshdlrdata->eventhdlr != NULL);
    13717
    13718 /* catch bound change events of variables */
    13719 SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
    13720 }
    13721
    13722 return SCIP_OKAY;
    13723}
    13724
    13725/** creates and captures a cumulative constraint
    13726 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
    13727 * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
    13728 *
    13729 * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
    13730 *
    13731 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13732 */
    13734 SCIP* scip, /**< SCIP data structure */
    13735 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13736 const char* name, /**< name of constraint */
    13737 int nvars, /**< number of variables (jobs) */
    13738 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    13739 int* durations, /**< array containing corresponding durations */
    13740 int* demands, /**< array containing corresponding demands */
    13741 int capacity /**< available cumulative capacity */
    13742 )
    13743{
    13744 assert(scip != NULL);
    13745
    13746 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
    13748
    13749 return SCIP_OKAY;
    13750}
    13751
    13752/** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
    13754 SCIP* scip, /**< SCIP data structure */
    13755 SCIP_CONS* cons, /**< constraint data */
    13756 int hmin /**< left bound of time axis to be considered */
    13757 )
    13758{
    13759 SCIP_CONSDATA* consdata;
    13760 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13761 {
    13762 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13763 return SCIP_INVALIDCALL;
    13764 }
    13765
    13766 consdata = SCIPconsGetData(cons);
    13767 assert(consdata != NULL);
    13768
    13769 if( hmin < 0 || hmin > consdata->hmax )
    13770 {
    13771 SCIPerrorMessage("invalid value of hmin for cumulative constraint <%s>\n",
    13772 SCIPconsGetName(cons));
    13773 return SCIP_INVALIDCALL;
    13774 }
    13775
    13776 consdata->hmin = hmin;
    13777
    13778 return SCIP_OKAY;
    13779}
    13780
    13781/** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
    13783 SCIP* scip, /**< SCIP data structure */
    13784 SCIP_CONS* cons /**< constraint */
    13785 )
    13786{
    13787 SCIP_CONSDATA* consdata;
    13788 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13789 {
    13790 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13791 SCIPABORT();
    13792 return 0; /*lint !e527*/
    13793 }
    13794
    13795 consdata = SCIPconsGetData(cons);
    13796 assert(consdata != NULL);
    13797
    13798 return consdata->hmin;
    13799}
    13800
    13801/** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
    13803 SCIP* scip, /**< SCIP data structure */
    13804 SCIP_CONS* cons, /**< constraint data */
    13805 int hmax /**< right bound of time axis to be considered */
    13806 )
    13807{
    13808 SCIP_CONSDATA* consdata;
    13809 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13810 {
    13811 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13812 SCIPABORT();
    13813 return SCIP_INVALIDCALL; /*lint !e527*/
    13814 }
    13815
    13816 consdata = SCIPconsGetData(cons);
    13817 assert(consdata != NULL);
    13818
    13819 if( hmax < consdata->hmin )
    13820 {
    13821 SCIPerrorMessage("invalid value of hmax for cumulative constraint <%s>\n",
    13822 SCIPconsGetName(cons));
    13823 return SCIP_INVALIDCALL;
    13824 }
    13825
    13826 consdata->hmax = hmax;
    13827
    13828 return SCIP_OKAY;
    13829}
    13830
    13831/** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
    13833 SCIP* scip, /**< SCIP data structure */
    13834 SCIP_CONS* cons /**< constraint */
    13835 )
    13836{
    13837 SCIP_CONSDATA* consdata;
    13838 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13839 {
    13840 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13841 SCIPABORT();
    13842 return 0; /*lint !e527*/
    13843 }
    13844
    13845 consdata = SCIPconsGetData(cons);
    13846 assert(consdata != NULL);
    13847
    13848 return consdata->hmax;
    13849}
    13850
    13851/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
    13853 SCIP* scip, /**< SCIP data structure */
    13854 SCIP_CONS* cons /**< constraint data */
    13855 )
    13856{
    13857 SCIP_CONSDATA* consdata;
    13858
    13859 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13860 {
    13861 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13862 SCIPABORT();
    13863 return NULL; /*lint !e527*/
    13864 }
    13865
    13866 consdata = SCIPconsGetData(cons);
    13867 assert(consdata != NULL);
    13868
    13869 return consdata->vars;
    13870}
    13871
    13872/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
    13874 SCIP* scip, /**< SCIP data structure */
    13875 SCIP_CONS* cons /**< constraint data */
    13876 )
    13877{
    13878 SCIP_CONSDATA* consdata;
    13879
    13880 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13881 {
    13882 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13883 SCIPABORT();
    13884 return -1; /*lint !e527*/
    13885 }
    13886
    13887 consdata = SCIPconsGetData(cons);
    13888 assert(consdata != NULL);
    13889
    13890 return consdata->nvars;
    13891}
    13892
    13893/** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
    13895 SCIP* scip, /**< SCIP data structure */
    13896 SCIP_CONS* cons /**< constraint data */
    13897 )
    13898{
    13899 SCIP_CONSDATA* consdata;
    13900
    13901 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13902 {
    13903 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13904 SCIPABORT();
    13905 return -1; /*lint !e527*/
    13906 }
    13907
    13908 consdata = SCIPconsGetData(cons);
    13909 assert(consdata != NULL);
    13910
    13911 return consdata->capacity;
    13912}
    13913
    13914/** returns the durations of the cumulative constraint */ /*lint -e{715}*/
    13916 SCIP* scip, /**< SCIP data structure */
    13917 SCIP_CONS* cons /**< constraint data */
    13918 )
    13919{
    13920 SCIP_CONSDATA* consdata;
    13921
    13922 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13923 {
    13924 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13925 SCIPABORT();
    13926 return NULL; /*lint !e527*/
    13927 }
    13928
    13929 consdata = SCIPconsGetData(cons);
    13930 assert(consdata != NULL);
    13931
    13932 return consdata->durations;
    13933}
    13934
    13935/** returns the demands of the cumulative constraint */ /*lint -e{715}*/
    13937 SCIP* scip, /**< SCIP data structure */
    13938 SCIP_CONS* cons /**< constraint data */
    13939 )
    13940{
    13941 SCIP_CONSDATA* consdata;
    13942
    13943 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13944 {
    13945 SCIPerrorMessage("constraint is not a cumulative constraint\n");
    13946 SCIPABORT();
    13947 return NULL; /*lint !e527*/
    13948 }
    13949
    13950 consdata = SCIPconsGetData(cons);
    13951 assert(consdata != NULL);
    13952
    13953 return consdata->demands;
    13954}
    13955
    13956/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
    13957 * given solution is satisfied
    13958 */
    13960 SCIP* scip, /**< SCIP data structure */
    13961 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    13962 int nvars, /**< number of variables (jobs) */
    13963 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    13964 int* durations, /**< array containing corresponding durations */
    13965 int* demands, /**< array containing corresponding demands */
    13966 int capacity, /**< available cumulative capacity */
    13967 int hmin, /**< left bound of time axis to be considered (including hmin) */
    13968 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    13969 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
    13970 SCIP_CONS* cons, /**< constraint which is checked */
    13971 SCIP_Bool printreason /**< should the reason for the violation be printed? */
    13972 )
    13973{
    13974 assert(scip != NULL);
    13975 assert(violated != NULL);
    13976
    13977 SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
    13978 violated, cons, printreason) );
    13979
    13980 return SCIP_OKAY;
    13981}
    13982
    13983/** normalize cumulative condition */ /*lint -e{715}*/
    13985 SCIP* scip, /**< SCIP data structure */
    13986 int nvars, /**< number of start time variables (activities) */
    13987 SCIP_VAR** vars, /**< array of start time variables */
    13988 int* durations, /**< array of durations */
    13989 int* demands, /**< array of demands */
    13990 int* capacity, /**< pointer to store the changed cumulative capacity */
    13991 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    13992 int* nchgsides /**< pointer to count number of side changes */
    13993 )
    13994{ /*lint --e{715}*/
    13995 normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
    13996
    13997 return SCIP_OKAY;
    13998}
    13999
    14000/** searches for a time point within the cumulative condition were the cumulative condition can be split */
    14002 SCIP* scip, /**< SCIP data structure */
    14003 int nvars, /**< number of variables (jobs) */
    14004 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    14005 int* durations, /**< array containing corresponding durations */
    14006 int* demands, /**< array containing corresponding demands */
    14007 int capacity, /**< available cumulative capacity */
    14008 int* hmin, /**< pointer to store the left bound of the effective horizon */
    14009 int* hmax, /**< pointer to store the right bound of the effective horizon */
    14010 int* split /**< point were the cumulative condition can be split */
    14011 )
    14012{
    14013 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
    14014 hmin, hmax, split) );
    14015
    14016 return SCIP_OKAY;
    14017}
    14018
    14019/** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
    14021 SCIP* scip, /**< SCIP data structure */
    14022 int nvars, /**< number of start time variables (activities) */
    14023 SCIP_VAR** vars, /**< array of start time variables */
    14024 int* durations, /**< array of durations */
    14025 int hmin, /**< left bound of time axis to be considered */
    14026 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    14027 SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
    14028 SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
    14029 SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
    14030 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
    14031 int* nfixedvars, /**< pointer to store the number of fixed variables */
    14032 int* nchgsides, /**< pointer to store the number of changed sides */
    14033 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    14034 )
    14035{
    14036 if( nvars <= 1 )
    14037 return SCIP_OKAY;
    14038
    14039 /* presolve constraint form the earlier start time point of view */
    14040 SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
    14041 irrelevants, nfixedvars, nchgsides, cutoff) );
    14042
    14043 /* presolve constraint form the latest completion time point of view */
    14044 SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
    14045 irrelevants, nfixedvars, nchgsides, cutoff) );
    14046
    14047 return SCIP_OKAY;
    14048}
    14049
    14050/** propagate the given cumulative condition */
    14052 SCIP* scip, /**< SCIP data structure */
    14053 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
    14054 int nvars, /**< number of variables (jobs) */
    14055 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    14056 int* durations, /**< array containing corresponding durations */
    14057 int* demands, /**< array containing corresponding demands */
    14058 int capacity, /**< available cumulative capacity */
    14059 int hmin, /**< left bound of time axis to be considered (including hmin) */
    14060 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    14061 SCIP_CONS* cons, /**< constraint which gets propagated */
    14062 int* nchgbds, /**< pointer to store the number of variable bound changes */
    14063 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    14064 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    14065 SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
    14066 )
    14067{
    14068 SCIP_CONSHDLR* conshdlr;
    14069 SCIP_CONSHDLRDATA* conshdlrdata;
    14070 SCIP_Bool redundant;
    14071
    14072 assert(scip != NULL);
    14073 assert(cons != NULL);
    14074 assert(initialized != NULL);
    14075 assert(*initialized == FALSE);
    14076 assert(cutoff != NULL);
    14077 assert(*cutoff == FALSE);
    14078
    14079 /* find the cumulative constraint handler */
    14080 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    14081 if( conshdlr == NULL )
    14082 {
    14083 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
    14084 return SCIP_PLUGINNOTFOUND;
    14085 }
    14086
    14087 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    14088 assert(conshdlrdata != NULL);
    14089
    14090 redundant = FALSE;
    14091
    14092 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
    14093 nvars, vars, durations, demands, capacity, hmin, hmax, cons,
    14094 nchgbds, &redundant, initialized, explanation, cutoff) );
    14095
    14096 return SCIP_OKAY;
    14097}
    14098
    14099/** resolve propagation w.r.t. the cumulative condition */
    14101 SCIP* scip, /**< SCIP data structure */
    14102 int nvars, /**< number of start time variables (activities) */
    14103 SCIP_VAR** vars, /**< array of start time variables */
    14104 int* durations, /**< array of durations */
    14105 int* demands, /**< array of demands */
    14106 int capacity, /**< cumulative capacity */
    14107 int hmin, /**< left bound of time axis to be considered (including hmin) */
    14108 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    14109 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
    14110 int inferinfo, /**< the user information */
    14111 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
    14112 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
    14113 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
    14114 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    14115 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
    14116 )
    14117{
    14118 SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    14119 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
    14120
    14121 return SCIP_OKAY;
    14122}
    14123
    14124/** this method visualizes the cumulative structure in GML format */
    14126 SCIP* scip, /**< SCIP data structure */
    14127 SCIP_CONS* cons /**< cumulative constraint */
    14128 )
    14129{
    14130 SCIP_CONSDATA* consdata;
    14131 SCIP_HASHTABLE* vars;
    14132 FILE* file;
    14133 SCIP_VAR* var;
    14134 char filename[SCIP_MAXSTRLEN];
    14135 int nvars;
    14136 int v;
    14137
    14138 SCIP_RETCODE retcode = SCIP_OKAY;
    14139
    14140 /* open file */
    14141 (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
    14142 file = fopen(filename, "w");
    14143
    14144 /* check if the file was open */
    14145 if( file == NULL )
    14146 {
    14147 SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
    14148 SCIPprintSysError(filename);
    14149 return SCIP_FILECREATEERROR;
    14150 }
    14151
    14152 consdata = SCIPconsGetData(cons);
    14153 assert(consdata != NULL);
    14154
    14155 nvars = consdata->nvars;
    14156
    14157 SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
    14158 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
    14159
    14160 /* create opening of the GML format */
    14162
    14163 for( v = 0; v < nvars; ++v )
    14164 {
    14165 char color[SCIP_MAXSTRLEN];
    14166
    14167 var = consdata->vars[v];
    14168 assert(var != NULL);
    14169
    14170 SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
    14171
    14172 if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
    14173 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
    14174 else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
    14175 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
    14176 else
    14177 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
    14178
    14179 SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
    14180 }
    14181
    14182 for( v = 0; v < nvars; ++v )
    14183 {
    14184 SCIP_VAR** vbdvars;
    14185 int nvbdvars;
    14186 int b;
    14187
    14188 var = consdata->vars[v];
    14189 assert(var != NULL);
    14190
    14191 vbdvars = SCIPvarGetVlbVars(var);
    14192 nvbdvars = SCIPvarGetNVlbs(var);
    14193
    14194 for( b = 0; b < nvbdvars; ++b )
    14195 {
    14196 if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
    14197 {
    14198 SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
    14199 }
    14200 }
    14201
    14202#ifdef SCIP_MORE_OUTPUT
    14203 /* define to also output variable bounds */
    14204 vbdvars = SCIPvarGetVubVars(var);
    14205 nvbdvars = SCIPvarGetNVubs(var);
    14206
    14207 for( b = 0; b < nvbdvars; ++b )
    14208 {
    14209 if( SCIPhashtableExists(vars, vbdvars[b]) )
    14210 {
    14211 SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
    14212 }
    14213 }
    14214#endif
    14215 }
    14216
    14217 /* create closing of the GML format */
    14218 SCIPgmlWriteClosing(file);
    14219TERMINATE:
    14220 /* close file */
    14221 fclose(file);
    14222
    14223 SCIPhashtableFree(&vars);
    14224
    14225 return retcode;
    14226}
    14227
    14228/** sets method to solve an individual cumulative condition */
    14230 SCIP* scip, /**< SCIP data structure */
    14231 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
    14232 )
    14233{
    14234 SCIP_CONSHDLR* conshdlr;
    14235 SCIP_CONSHDLRDATA* conshdlrdata;
    14236
    14237 /* find the cumulative constraint handler */
    14238 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    14239 if( conshdlr == NULL )
    14240 {
    14241 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
    14242 return SCIP_PLUGINNOTFOUND;
    14243 }
    14244
    14245 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    14246 assert(conshdlrdata != NULL);
    14247
    14248 conshdlrdata->solveCumulative = solveCumulative;
    14249
    14250 return SCIP_OKAY;
    14251}
    14252
    14253/** solves given cumulative condition as independent sub problem
    14254 *
    14255 * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
    14256 * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
    14257 * solver was interrupted.
    14258 */
    14260 SCIP* scip, /**< SCIP data structure */
    14261 int njobs, /**< number of jobs (activities) */
    14262 SCIP_Real* ests, /**< array with the earlier start time for each job */
    14263 SCIP_Real* lsts, /**< array with the latest start time for each job */
    14264 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
    14265 int* durations, /**< array of durations */
    14266 int* demands, /**< array of demands */
    14267 int capacity, /**< cumulative capacity */
    14268 int hmin, /**< left bound of time axis to be considered (including hmin) */
    14269 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    14270 SCIP_Real timelimit, /**< time limit for solving in seconds */
    14271 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
    14272 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
    14273 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
    14274 SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
    14275 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
    14276 SCIP_Bool* error /**< pointer to store if an error occurred */
    14277 )
    14278{
    14279 SCIP_CONSHDLR* conshdlr;
    14280 SCIP_CONSHDLRDATA* conshdlrdata;
    14281
    14282 (*solved) = TRUE;
    14283 (*infeasible) = FALSE;
    14284 (*unbounded) = FALSE;
    14285 (*error) = FALSE;
    14286
    14287 if( njobs == 0 )
    14288 return SCIP_OKAY;
    14289
    14290 /* find the cumulative constraint handler */
    14291 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    14292 if( conshdlr == NULL )
    14293 {
    14294 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
    14295 (*error) = TRUE;
    14296 return SCIP_PLUGINNOTFOUND;
    14297 }
    14298
    14299 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    14300 assert(conshdlrdata != NULL);
    14301
    14302 /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
    14303 if( timelimit > 0.0 && memorylimit > 10 )
    14304 {
    14305 SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
    14306 hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
    14307 }
    14308
    14309 return SCIP_OKAY;
    14310}
    14311
    14312/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
    14313 * completion time
    14314 */
    14316 SCIP* scip, /**< SCIP data structure */
    14317 SCIP_PROFILE* profile, /**< resource profile */
    14318 int nvars, /**< number of variables (jobs) */
    14319 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    14320 int* durations, /**< array containing corresponding durations */
    14321 int* demands /**< array containing corresponding demands */
    14322 )
    14323{
    14324 SCIP_VAR* var;
    14325 SCIP_HASHMAP* addedvars;
    14326 int* copydemands;
    14327 int* perm;
    14328 int duration;
    14329 int impliedest;
    14330 int est;
    14331 int impliedlct;
    14332 int lct;
    14333 int v;
    14334
    14335 /* create hash map for variables which are added, mapping to their duration */
    14336 SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
    14337
    14338 SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
    14339 SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
    14340
    14341 /* sort variables w.r.t. job demands */
    14342 for( v = 0; v < nvars; ++v )
    14343 {
    14344 copydemands[v] = demands[v];
    14345 perm[v] = v;
    14346 }
    14347 SCIPsortDownIntInt(copydemands, perm, nvars);
    14348
    14349 /* add each job with its earliest start and latest completion time into the resource profile */
    14350 for( v = 0; v < nvars; ++v )
    14351 {
    14352 int idx;
    14353
    14354 idx = perm[v];
    14355 assert(idx >= 0 && idx < nvars);
    14356
    14357 var = vars[idx];
    14358 assert(var != NULL);
    14359
    14360 duration = durations[idx];
    14361 assert(duration > 0);
    14362
    14364 SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
    14365
    14366 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
    14367 SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
    14368
    14369 if( impliedest < impliedlct )
    14370 {
    14371 SCIP_Bool infeasible;
    14372 int pos;
    14373
    14374 SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
    14375 assert(!infeasible);
    14376 assert(pos == -1);
    14377 }
    14378
    14379 if( est == impliedest && lct == impliedlct )
    14380 {
    14381 SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
    14382 }
    14383 }
    14384
    14385 SCIPfreeBufferArray(scip, &copydemands);
    14386 SCIPfreeBufferArray(scip, &perm);
    14387
    14388 SCIPhashmapFree(&addedvars);
    14389
    14390 return SCIP_OKAY;
    14391}
    14392
    14393/** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
    14395 SCIP* scip, /**< SCIP data structure */
    14396 SCIP_PROFILE* profile, /**< worst case resource profile */
    14397 int capacity /**< capacity to check */
    14398 )
    14399{
    14400 int* timepoints;
    14401 int* loads;
    14402 int ntimepoints;
    14403 int t;
    14404
    14405 ntimepoints = SCIPprofileGetNTimepoints(profile);
    14406 timepoints = SCIPprofileGetTimepoints(profile);
    14407 loads = SCIPprofileGetLoads(profile);
    14408
    14409 /* find first time point which potentially violates the capacity restriction */
    14410 for( t = 0; t < ntimepoints - 1; ++t )
    14411 {
    14412 /* check if the time point exceed w.r.t. worst case profile the capacity */
    14413 if( loads[t] > capacity )
    14414 {
    14415 assert(t == 0 || loads[t-1] <= capacity);
    14416 return timepoints[t];
    14417 }
    14418 }
    14419
    14420 return INT_MAX;
    14421}
    14422
    14423/** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */ /*lint -e{715}*/
    14425 SCIP* scip, /**< SCIP data structure */
    14426 SCIP_PROFILE* profile, /**< worst case profile */
    14427 int capacity /**< capacity to check */
    14428 )
    14429{
    14430 int* timepoints;
    14431 int* loads;
    14432 int ntimepoints;
    14433 int t;
    14434
    14435 ntimepoints = SCIPprofileGetNTimepoints(profile);
    14436 timepoints = SCIPprofileGetTimepoints(profile);
    14437 loads = SCIPprofileGetLoads(profile);
    14438
    14439 /* find last time point which potentially violates the capacity restriction */
    14440 for( t = ntimepoints - 1; t >= 0; --t )
    14441 {
    14442 /* check if at time point t the worst case resource profile exceeds the capacity */
    14443 if( loads[t] > capacity )
    14444 {
    14445 assert(t == ntimepoints-1 || loads[t+1] <= capacity);
    14446 return timepoints[t+1];
    14447 }
    14448 }
    14449
    14450 return INT_MIN;
    14451}
    static long bound
    static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
    SCIP_VAR ** b
    Definition: circlepacking.c:65
    SCIP_Real * r
    Definition: circlepacking.c:59
    enum Proprule PROPRULE
    Definition: cons_and.c:173
    Proprule
    Definition: cons_and.c:166
    static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
    enum Proprule PROPRULE
    static SCIP_DECL_CONSPROP(consPropCumulative)
    static int inferInfoGetData1(INFERINFO inferinfo)
    static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
    #define DEFAULT_USEBDWIDENING
    #define CONSHDLR_NEEDSCONS
    #define DEFAULT_SEPAOLD
    #define CONSHDLR_SEPAFREQ
    static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
    static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
    static void consdataCalcSignature(SCIP_CONSDATA *consdata)
    static SCIP_RETCODE propagateUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *lsts, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    #define DEFAULT_NORMALIZE
    static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
    static SCIP_RETCODE collectIntVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***activevars, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, int *lhs)
    static SCIP_RETCODE getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
    static SCIP_DECL_CONSINITPRE(consInitpreCumulative)
    #define DEFAULT_DETECTVARBOUNDS
    static SCIP_RETCODE createConsCumulative(SCIP *scip, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    #define CONSHDLR_CHECKPRIORITY
    static SCIP_RETCODE presolveConsEst(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
    #define DEFAULT_TTEFINFER
    #define CONSHDLR_DESC
    static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
    static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
    #define DEFAULT_USECOVERCUTS
    static SCIP_DECL_EVENTEXEC(eventExecCumulative)
    static SCIP_Longint computeCoreWithInterval(int begin, int end, int ect, int lst)
    static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
    #define DEFAULT_LOCALCUTS
    static SCIP_DECL_CONSCOPY(consCopyCumulative)
    static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
    static SCIP_RETCODE checkOverloadViaThetaTree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool propest, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
    #define DEFAULT_COEFTIGHTENING
    static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
    static SCIP_RETCODE createPrecedenceCons(SCIP *scip, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, int distance)
    #define DEFAULT_MAXNODES
    static SCIP_Bool isConsIndependently(SCIP_CONS *cons)
    #define CONSHDLR_PROP_TIMING
    static SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
    static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated, SCIP_Bool *cutoff)
    static SCIP_RETCODE analyzeConflictOverload(SCIP *scip, SCIP_BTNODE **leaves, int capacity, int nleaves, int est, int lct, int reportedenergy, SCIP_Bool propest, int shift, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
    static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
    static void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
    static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
    static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
    static void consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file)
    #define CONSHDLR_MAXPREROUNDS
    static SCIP_RETCODE tightenUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int lst, int lct, int begin, int end, SCIP_Longint energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    static SCIP_DECL_CONSCHECK(consCheckCumulative)
    static SCIP_RETCODE propagateTimetable(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
    static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
    static SCIP_RETCODE collectBranchingCands(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nbranchcands)
    static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
    static int computeEnergyContribution(SCIP_BTNODE *node)
    #define DEFAULT_PRESOLPAIRWISE
    static SCIP_RETCODE inferboundsEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_BT *tree, SCIP_BTNODE **leaves, int capacity, int ncands, SCIP_Bool propest, int shift, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
    static SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
    static SCIP_RETCODE presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
    #define DEFAULT_EFINFER
    #define CONSHDLR_SEPAPRIORITY
    static int boundedConvertRealToInt(SCIP *scip, SCIP_Real real)
    static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
    static SCIP_RETCODE createCoreProfile(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    static SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
    static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
    static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
    static SCIP_DECL_SORTPTRCOMP(compNodeEst)
    #define DEFAULT_EFCHECK
    static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
    static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
    static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
    static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
    static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
    static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
    #define DEFAULT_DETECTDISJUNCTIVE
    static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
    static INFERINFO getInferInfo(PROPRULE proprule, int data1, int data2)
    static SCIP_RETCODE setupAndSolveCumulativeSubscip(SCIP *subscip, SCIP_Real *objvals, int *durations, int *demands, int njobs, int capacity, int hmin, int hmax, SCIP_Longint maxnodes, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *solved, SCIP_Bool *error)
    static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
    static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
    static int computeOverlap(int begin, int end, int est, int lst, int duration)
    static SCIP_Longint computeTotalEnergy(int *durations, int *demands, int njobs)
    static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
    static SCIP_RETCODE respropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, INFERINFO inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation, SCIP_RESULT *result)
    static SCIP_DECL_CONSRESPROP(consRespropCumulative)
    static SCIP_RETCODE removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
    static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
    static INFERINFO intToInferInfo(int i)
    static void createSelectedSortedEventpointsSol(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *starttimes, int *endtimes, int *startindices, int *endindices, int *nvars, SCIP_Bool lower)
    static void updateEnvelope(SCIP *scip, SCIP_BTNODE *node)
    static SCIP_RETCODE propagateEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
    static SCIP_DECL_SORTINDCOMP(compNodedataLct)
    struct SCIP_NodeData SCIP_NODEDATA
    #define DEFAULT_CUTSASCONSS
    #define DEFAULT_DUALPRESOLVE
    static SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
    static SCIP_RETCODE analyzeEnergyRequirement(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int begin, int end, SCIP_VAR *infervar, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation)
    static SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
    static SCIP_RETCODE applyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_Real leftub, SCIP_Real rightlb, SCIP_Real *leftimpllbs, SCIP_Real *leftimplubs, SCIP_Real *leftproplbs, SCIP_Real *leftpropubs, SCIP_Real *rightimpllbs, SCIP_Real *rightimplubs, SCIP_Real *rightproplbs, SCIP_Real *rightpropubs, int *nfixedvars, SCIP_Bool *success, SCIP_Bool *cutoff)
    #define DEFAULT_TTEFCHECK
    static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
    @ PROPRULE_3_TTEF
    @ PROPRULE_0_INVALID
    @ PROPRULE_1_CORETIMES
    @ PROPRULE_2_EDGEFINDING
    static void normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
    static SCIP_Bool inferInfoIsValid(INFERINFO inferinfo)
    static void computeCoreEnergyAfter(SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
    static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
    static SCIP_DECL_CONSLOCK(consLockCumulative)
    static SCIP_RETCODE createCumulativeCons(SCIP *scip, const char *name, TCLIQUE_GRAPH *tcliquegraph, int *cliquenodes, int ncliquenodes)
    static void collectDataTTEF(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int hmin, int hmax, int *permests, int *ests, int *permlcts, int *lcts, int *ects, int *lsts, int *flexenergies)
    static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR **vars, SCIP_CONS **linkingconss, int *durations, int *demands, int nvars, int capacity, int hmin, int hmax, SCIP_Bool check)
    static SCIP_RETCODE createCoverCutsTimepoint(SCIP *scip, SCIP_CONS *cons, int *startvalues, int time)
    static SCIP_RETCODE tightenLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int ect, int lct, int begin, int end, SCIP_Longint energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
    static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
    static SCIP_RETCODE presolveConsLct(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
    static int inferInfoGetData2(INFERINFO inferinfo)
    static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
    static SCIP_RETCODE propagateCumulativeCondition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *redundant, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    static SCIP_RETCODE resolvePropagationCoretimes(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferdemand, int inferpeak, int relaxedpeak, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool usebdwidening, int *provedpeak, SCIP_Bool *explanation)
    static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
    static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
    static SCIP_RETCODE collectBinaryVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***vars, int **coefs, int *nvars, int *startindices, int curtime, int nstarted, int nfinished)
    #define DEFAULT_USEADJUSTEDJOBS
    static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
    static SCIP_DECL_CONSFREE(consFreeCumulative)
    static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
    static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
    static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
    static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
    static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
    static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
    static SCIP_DECL_CONSPRINT(consPrintCumulative)
    static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
    static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
    static void collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
    #define CONSHDLR_PROPFREQ
    static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, SCIP_Bool *cutoff)
    static SCIP_RETCODE computeImpliedLct(SCIP *scip, SCIP_VAR *var, int duration, SCIP_HASHMAP *addedvars, int *lct)
    static SCIP_RETCODE findCumulativeConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
    static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
    static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
    static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
    static SCIP_RETCODE analyseInfeasibelCoreInsertion(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferduration, int inferdemand, int inferpeak, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
    static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
    #define CONSHDLR_PRESOLTIMING
    static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
    static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
    static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
    static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
    static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
    static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
    static SCIP_RETCODE coretimesUpdateLb(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *infeasible)
    static SCIP_RETCODE solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
    static SCIP_DECL_CONSDELETE(consDeleteCumulative)
    static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
    static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
    static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
    #define CONSHDLR_EAGERFREQ
    #define DEFAULT_USEBINVARS
    #define EVENTHDLR_DESC
    static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
    static SCIP_RETCODE coretimesUpdateUb(SCIP *scip, SCIP_VAR *var, int duration, int demand, int capacity, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds)
    static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
    static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
    #define DEFAULT_MAXTIME
    static int computeEstOmegaset(SCIP *scip, int duration, int demand, int capacity, int est, int lct, int energy)
    #define CONSHDLR_ENFOPRIORITY
    struct InferInfo INFERINFO
    static SCIP_RETCODE propagateTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA *nodedatas, int *nodedataidx, int *nnodedatas)
    static SCIP_DECL_CONSPARSE(consParseCumulative)
    static SCIP_DECL_CONSPRESOL(consPresolCumulative)
    static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
    #define CONSHDLR_DELAYSEPA
    static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
    #define DEFAULT_FILLBRANCHCANDS
    static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
    static SCIP_RETCODE propagateLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *ects, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
    static TCLIQUE_NEWSOL(tcliqueNewsolClique)
    static SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
    #define DEFAULT_TTINFER
    static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
    static SCIP_RETCODE removeOversizedJobs(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *nchgcoefs, int *naddconss, SCIP_Bool *cutoff)
    static SCIP_DECL_CONSINITLP(consInitlpCumulative)
    static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
    #define CONSHDLR_NAME
    static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
    static int inferInfoToInt(INFERINFO inferinfo)
    static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
    #define EVENTHDLR_NAME
    static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
    static void traceLambdaEnergy(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
    static SCIP_DECL_CONSTRANS(consTransCumulative)
    static SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
    static SCIP_RETCODE separateConsBinaryRepresentation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
    static void normalizeCumulativeCondition(SCIP *scip, int nvars, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
    static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
    #define CONSHDLR_DELAYPROP
    static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
    #define DEFAULT_DISJUNCTIVE
    static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
    static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss, SCIP_Bool *infeasible)
    static SCIP_RETCODE checkCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
    constraint handler for cumulative constraints
    Constraint handler for knapsack constraints of the form , x binary and .
    constraint handler for linking binary variables to a linking (continuous or integer) variable
    static SCIP_RETCODE solveCumulative(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool local, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define SCIP_UNKNOWN
    Definition: def.h:179
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_CALL_TERMINATE(retcode, x, TERM)
    Definition: def.h:376
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define MIN3(x, y, z)
    Definition: def.h:232
    #define SCIPABORT()
    Definition: def.h:327
    #define SCIP_LONGINT_MAX
    Definition: def.h:142
    #define SCIP_CALL(x)
    Definition: def.h:355
    #define SCIP_CALL_FINALLY(x, y)
    Definition: def.h:397
    #define nnodes
    Definition: gastrans.c:74
    static const NodeData nodedata[]
    Definition: gastrans.c:83
    void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
    Definition: misc.c:9023
    SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
    Definition: misc.c:8892
    SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
    Definition: misc.c:9135
    SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
    Definition: misc.c:9034
    void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
    Definition: misc.c:8817
    SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
    Definition: misc.c:8932
    void * SCIPbtnodeGetData(SCIP_BTNODE *node)
    Definition: misc.c:8862
    SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
    Definition: misc.c:8753
    SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
    Definition: misc.c:8960
    void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
    Definition: misc.c:8995
    SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
    Definition: misc.c:8942
    void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
    Definition: misc.c:9009
    SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
    Definition: misc.c:8872
    void SCIPbtFree(SCIP_BT **tree)
    Definition: misc.c:9053
    SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
    Definition: misc.c:8882
    void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
    Definition: misc.c:9158
    SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
    Definition: misc.c:8922
    SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
    Definition: misc.c:9145
    int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPpropCumulativeCondition(SCIP *scip, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
    SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
    SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
    SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
    Definition: cons_setppc.c:9442
    int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
    SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *linkvar)
    SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
    SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
    SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
    int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
    SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *linkvar)
    SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_RETCODE SCIPcheckCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
    SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
    int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPsolveCumulative(SCIP *scip, int njobs, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Real *objvals, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
    SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *linkvar, SCIP_VAR **binvars, SCIP_Real *vals, int nbinvars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
    SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
    Definition: cons_setppc.c:9573
    SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPrespropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool *explanation, SCIP_RESULT *result)
    int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
    SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
    SCIP_RETCODE SCIPpresolveCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
    SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_Real * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
    int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
    SCIP_RETCODE SCIPcreateConsCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
    SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
    SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
    Definition: scip_copy.c:713
    void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
    Definition: misc.c:501
    void SCIPgmlWriteClosing(FILE *file)
    Definition: misc.c:703
    void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
    Definition: misc.c:687
    void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
    Definition: misc.c:643
    SCIP_Bool SCIPisTransformed(SCIP *scip)
    Definition: scip_general.c:647
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    SCIP_RETCODE SCIPfree(SCIP **scip)
    Definition: scip_general.c:402
    SCIP_RETCODE SCIPcreate(SCIP **scip)
    Definition: scip_general.c:370
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_prob.c:1907
    int SCIPgetNCheckConss(SCIP *scip)
    Definition: scip_prob.c:3762
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3420
    int SCIPgetNConss(SCIP *scip)
    Definition: scip_prob.c:3620
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
    Definition: scip_prob.c:182
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3179
    SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3482
    void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
    Definition: misc.c:2348
    SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2647
    SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
    Definition: misc.c:2298
    SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2535
    SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:4067
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
    Definition: scip_message.c:88
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
    Definition: misc.c:9197
    SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
    Definition: misc.c:11162
    SCIP_RETCODE SCIPapplyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_BOUNDTYPE boundtype, SCIP_Real bound, int maxproprounds, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Real *proplbs, SCIP_Real *propubs, SCIP_Bool *cutoff)
    SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:111
    SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:83
    SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
    Definition: scip_param.c:545
    SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
    Definition: scip_param.c:904
    SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
    Definition: scip_param.c:307
    SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
    Definition: scip_param.c:882
    SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
    Definition: scip_param.c:661
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
    Definition: scip_param.c:429
    SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
    Definition: scip_param.c:603
    void SCIPswapInts(int *value1, int *value2)
    Definition: misc.c:10485
    void SCIPswapPointers(void **pointer1, void **pointer2)
    Definition: misc.c:10511
    SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
    Definition: scip_branch.c:673
    SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
    Definition: scip_branch.c:1099
    SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
    SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
    SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
    SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
    SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
    SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
    SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
    SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
    SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
    SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
    Definition: scip_cons.c:808
    void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
    Definition: cons.c:4346
    SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
    Definition: scip_cons.c:540
    SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
    Definition: scip_cons.c:831
    SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
    Definition: scip_cons.c:492
    SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
    Definition: scip_cons.c:235
    SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
    Definition: scip_cons.c:281
    SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
    Definition: scip_cons.c:181
    SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
    Definition: scip_cons.c:578
    SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
    Definition: scip_cons.c:372
    SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
    Definition: scip_cons.c:323
    const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4316
    SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
    Definition: scip_cons.c:516
    SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
    Definition: scip_cons.c:347
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
    Definition: scip_cons.c:468
    SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
    Definition: scip_cons.c:624
    SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4336
    SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
    Definition: scip_cons.c:601
    SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
    Definition: scip_cons.c:647
    SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
    Definition: scip_cons.c:854
    SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
    Definition: scip_cons.c:785
    SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
    Definition: cons.c:8419
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8648
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8409
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8558
    SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
    Definition: scip_cons.c:2536
    SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
    Definition: scip_cons.c:1625
    SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
    Definition: scip_cons.c:1296
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8588
    SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
    Definition: cons.c:8518
    SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
    Definition: cons.c:8698
    SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
    Definition: scip_cons.c:1271
    SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
    Definition: scip_cons.c:1321
    SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
    Definition: cons.c:8578
    SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
    Definition: cons.c:8450
    SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    Definition: scip_cons.c:997
    SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
    Definition: cons.c:8608
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8628
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8389
    SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1812
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8638
    SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
    Definition: scip_cons.c:1524
    SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
    Definition: cons.c:8668
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8568
    SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1138
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8658
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: scip_event.c:111
    const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:396
    SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:367
    SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:413
    SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
    Definition: scip_mem.c:126
    #define SCIPfreeBuffer(scip, ptr)
    Definition: scip_mem.h:134
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    SCIP_Longint SCIPgetMemUsed(SCIP *scip)
    Definition: scip_mem.c:100
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPreallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:128
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPduplicateBufferArray(scip, ptr, source, num)
    Definition: scip_mem.h:132
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPallocBuffer(scip, ptr)
    Definition: scip_mem.h:122
    #define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    #define SCIPfreeBufferArrayNull(scip, ptr)
    Definition: scip_mem.h:137
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    SCIP_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1581
    SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1398
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_lp.c:1646
    SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
    Definition: scip_lp.c:2176
    SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
    Definition: scip_lp.c:2131
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1974
    SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
    Definition: lp.c:17917
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2981
    void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
    Definition: scip_sol.c:453
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
    Definition: scip_solve.c:3603
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2635
    int SCIPgetNRuns(SCIP *scip)
    SCIP_Real SCIPgetSolvingTime(SCIP *scip)
    Definition: scip_timing.c:378
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
    SCIP_Bool SCIPinRepropagation(SCIP *scip)
    Definition: scip_tree.c:146
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
    Definition: var.c:23514
    SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6401
    int SCIPvarGetNVlbs(SCIP_VAR *var)
    Definition: var.c:24482
    SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
    Definition: scip_var.c:5210
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24504
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23642
    SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
    Definition: scip_var.c:2119
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23386
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4386
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
    Definition: var.c:23430
    SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
    Definition: scip_var.c:10550
    SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:7069
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6651
    SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
    Definition: scip_var.c:728
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
    Definition: scip_var.c:2499
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24142
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23652
    SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
    Definition: scip_var.c:5118
    SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
    Definition: scip_var.c:8621
    SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
    Definition: scip_var.c:5296
    SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2872
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23662
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
    Definition: var.c:24514
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24524
    SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
    Definition: var.c:23524
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24494
    SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
    Definition: scip_var.c:120
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:11057
    SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
    Definition: scip_var.c:10318
    SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6964
    SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2736
    int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
    Definition: var.c:17274
    SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
    Definition: scip_var.c:184
    SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
    Definition: var.c:24556
    SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
    Definition: var.c:24536
    SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
    Definition: var.c:24546
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4328
    SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
    Definition: scip_var.c:10984
    SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
    Definition: misc.c:7097
    int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
    Definition: misc.c:6904
    SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
    Definition: misc.c:6950
    int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
    Definition: misc.c:6894
    void SCIPprofileFree(SCIP_PROFILE **profile)
    Definition: misc.c:6846
    int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
    Definition: misc.c:6936
    int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
    Definition: misc.c:6914
    SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
    Definition: misc.c:6832
    int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
    Definition: misc.c:6924
    SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
    Definition: misc.c:7127
    void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
    Definition: misc.c:6862
    void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
    void SCIPsortInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
    void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
    void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
    void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
    Definition: misc.c:5581
    void SCIPsortInt(int *intarray, int len)
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
    Definition: misc.c:10985
    void SCIPprintSysError(const char *message)
    Definition: misc.c:10719
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    double real
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    #define SCIPdebugPrintCons(x, y, z)
    Definition: pub_message.h:102
    #define SCIPstatisticPrintf
    Definition: pub_message.h:126
    #define SCIPdebugMessage
    Definition: pub_message.h:96
    #define SCIPstatistic(x)
    Definition: pub_message.h:120
    SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
    default SCIP plugins
    static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
    Main separation function.
    Definition: sepa_flower.c:1221
    tclique user interface
    enum TCLIQUE_Status TCLIQUE_STATUS
    Definition: tclique.h:68
    int TCLIQUE_WEIGHT
    Definition: tclique.h:48
    void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
    struct TCLIQUE_Graph TCLIQUE_GRAPH
    Definition: tclique.h:49
    @ SCIP_CONFTYPE_PROPAGATION
    Definition: type_conflict.h:62
    struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
    Definition: type_cons.h:64
    #define SCIP_DECL_CONSEXITPRE(x)
    Definition: type_cons.h:180
    struct SCIP_ConsData SCIP_CONSDATA
    Definition: type_cons.h:65
    struct SCIP_EventData SCIP_EVENTDATA
    Definition: type_event.h:179
    #define SCIP_EVENTTYPE_BOUNDTIGHTENED
    Definition: type_event.h:125
    @ SCIP_BOUNDTYPE_UPPER
    Definition: type_lp.h:58
    @ SCIP_BOUNDTYPE_LOWER
    Definition: type_lp.h:57
    enum SCIP_BoundType SCIP_BOUNDTYPE
    Definition: type_lp.h:60
    @ SCIP_PARAMEMPHASIS_CPSOLVER
    Definition: type_paramset.h:72
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_FEASIBLE
    Definition: type_result.h:45
    @ SCIP_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_UNBOUNDED
    Definition: type_result.h:47
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    @ SCIP_SUCCESS
    Definition: type_result.h:58
    @ SCIP_INFEASIBLE
    Definition: type_result.h:46
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_FILECREATEERROR
    Definition: type_retcode.h:48
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_PLUGINNOTFOUND
    Definition: type_retcode.h:54
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_PROBLEM
    Definition: type_set.h:45
    @ SCIP_STAGE_PRESOLVING
    Definition: type_set.h:49
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53
    @ SCIP_STAGE_TRANSFORMING
    Definition: type_set.h:46
    @ SCIP_STATUS_OPTIMAL
    Definition: type_stat.h:43
    @ SCIP_STATUS_TOTALNODELIMIT
    Definition: type_stat.h:50
    @ SCIP_STATUS_BESTSOLLIMIT
    Definition: type_stat.h:60
    @ SCIP_STATUS_SOLLIMIT
    Definition: type_stat.h:59
    @ SCIP_STATUS_UNBOUNDED
    Definition: type_stat.h:45
    @ SCIP_STATUS_UNKNOWN
    Definition: type_stat.h:42
    @ SCIP_STATUS_PRIMALLIMIT
    Definition: type_stat.h:57
    @ SCIP_STATUS_GAPLIMIT
    Definition: type_stat.h:56
    @ SCIP_STATUS_USERINTERRUPT
    Definition: type_stat.h:47
    @ SCIP_STATUS_TERMINATE
    Definition: type_stat.h:48
    @ SCIP_STATUS_INFORUNBD
    Definition: type_stat.h:46
    @ SCIP_STATUS_STALLNODELIMIT
    Definition: type_stat.h:52
    @ SCIP_STATUS_TIMELIMIT
    Definition: type_stat.h:54
    @ SCIP_STATUS_INFEASIBLE
    Definition: type_stat.h:44
    @ SCIP_STATUS_NODELIMIT
    Definition: type_stat.h:49
    @ SCIP_STATUS_DUALLIMIT
    Definition: type_stat.h:58
    @ SCIP_STATUS_MEMLIMIT
    Definition: type_stat.h:55
    @ SCIP_STATUS_RESTARTLIMIT
    Definition: type_stat.h:62
    #define SCIP_PRESOLTIMING_ALWAYS
    Definition: type_timing.h:58
    #define SCIP_PRESOLTIMING_MEDIUM
    Definition: type_timing.h:53
    unsigned int SCIP_PRESOLTIMING
    Definition: type_timing.h:61
    #define SCIP_PRESOLTIMING_FAST
    Definition: type_timing.h:52
    #define SCIP_PRESOLTIMING_EXHAUSTIVE
    Definition: type_timing.h:54
    @ SCIP_VARTYPE_INTEGER
    Definition: type_var.h:65
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    @ SCIP_VARSTATUS_FIXED
    Definition: type_var.h:54
    @ SCIP_VARSTATUS_MULTAGGR
    Definition: type_var.h:56
    @ SCIP_VARSTATUS_AGGREGATED
    Definition: type_var.h:55
    @ SCIP_LOCKTYPE_MODEL
    Definition: type_var.h:141