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-2026 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 "tclique/tclique.h"
    55#include "scip/cons_linking.h"
    56#include "scip/cons_knapsack.h"
    57#include "scip/scipdefplugins.h"
    58
    59/**@name Constraint handler properties
    60 *
    61 * @{
    62 */
    63
    64/* constraint handler properties */
    65#define CONSHDLR_NAME "cumulative"
    66#define CONSHDLR_DESC "cumulative constraint handler"
    67#define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
    68#define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
    69#define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
    70#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
    71#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
    72#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
    73 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
    74#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
    75#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
    76#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
    77#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
    78
    79#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
    80#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
    81
    82/**@} */
    83
    84/**@name Default parameter values
    85 *
    86 * @{
    87 */
    88
    89/* default parameter values */
    90#define DEFAULT_MAXTIME 2000000000 /** < maximum range for time horizon (to avoid integer overflow) */
    91
    92/* separation */
    93#define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
    94#define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
    95#define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
    96#define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
    97#define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
    98
    99/* propagation */
    100#define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
    101#define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
    102#define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
    103#define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
    104#define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
    105#define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
    106
    107/* presolving */
    108#define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
    109#define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
    110#define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
    111#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
    112#define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
    113#define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
    114#define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
    115#define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
    116
    117/* enforcement */
    118#define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
    119
    120/* conflict analysis */
    121#define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
    122
    123/**@} */
    124
    125/**@name Event handler properties
    126 *
    127 * @{
    128 */
    129
    130#define EVENTHDLR_NAME "cumulative"
    131#define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
    132
    133/**@} */
    134
    135/*
    136 * Data structures
    137 */
    138
    139/** constraint data for cumulative constraints */
    140struct SCIP_ConsData
    141{
    142 SCIP_VAR** vars; /**< array of variable representing the start time of each job */
    143 SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
    144 SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
    145 SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
    146 SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
    147 SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
    148 SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
    149 int* demands; /**< array containing corresponding demands */
    150 int* durations; /**< array containing corresponding durations */
    151 SCIP_Real resstrength1; /**< stores the resource strength 1*/
    152 SCIP_Real resstrength2; /**< stores the resource strength 2 */
    153 SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
    154 SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
    155 SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
    156 SCIP_Real estimatedstrength;
    157 int nvars; /**< number of variables */
    158 int varssize; /**< size of the arrays */
    159 int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
    160 int demandrowssize; /**< size of array rows of demand rows */
    161 int nscoverrows; /**< number of rows of small cover cuts */
    162 int scoverrowssize; /**< size of array of small cover cuts */
    163 int nbcoverrows; /**< number of rows of big cover cuts */
    164 int bcoverrowssize; /**< size of array of big cover cuts */
    165 int capacity; /**< available cumulative capacity */
    166
    167 int hmin; /**< left bound of time axis to be considered (including hmin) */
    168 int hmax; /**< right bound of time axis to be considered (not including hmax) */
    169
    170 unsigned int signature; /**< constraint signature which is need for pairwise comparison */
    171
    172 unsigned int validsignature:1; /**< is the signature valid */
    173 unsigned int normalized:1; /**< is the constraint normalized */
    174 unsigned int covercuts:1; /**< cover cuts are created? */
    175 unsigned int propagated:1; /**< is constraint propagted */
    176 unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
    177 unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
    178
    179#ifdef SCIP_STATISTIC
    180 int maxpeak;
    181#endif
    182};
    183
    184/** constraint handler data */
    185struct SCIP_ConshdlrData
    186{
    187 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
    188
    189 SCIP_Bool usebinvars; /**< should the binary variables be used? */
    190 SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
    191 SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
    192 SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
    193 SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
    194 SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
    195 SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
    196 SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
    197 SCIP_Bool localcuts; /**< should cuts be added only locally? */
    198 SCIP_Bool usecovercuts; /**< should covering cuts be added? */
    199 SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
    200
    201 SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
    202
    203 SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
    204 SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
    205 SCIP_Bool normalize; /**< should demands and capacity be normalized? */
    206 SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
    207 SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
    208 SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
    209 SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
    210 SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
    211 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
    212
    213 int maxtime; /**< maximum range for time horizon (to avoid integer overflow) */
    214 SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
    215
    216 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
    217
    218 /* statistic values which are collected if SCIP_STATISTIC is defined */
    219#ifdef SCIP_STATISTIC
    220 SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
    221 SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
    222 SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
    223 SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
    224 SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
    225 SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
    226 SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
    227 SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
    228 SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
    229 SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
    230
    231 int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
    232 int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
    233 int nremovedlocks; /**< number of times a up or down lock was removed */
    234 int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
    235 int ndecomps; /**< number of times a constraint was decomposed */
    236 int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
    237 int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
    238 int naddedvarbounds; /**< number of added variable bounds constraints */
    239 int naddeddisjunctives; /**< number of added disjunctive constraints */
    240
    241 SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
    242#endif
    243};
    244
    245/**@name Inference Information Methods
    246 *
    247 * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
    248 * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
    249 * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
    250 *
    251 * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
    252 * change and the earliest start and latest completion time of all jobs in the conflict set.
    253 *
    254 * @{
    255 */
    256
    257/** Propagation rules */
    259{
    260 PROPRULE_0_INVALID = 0, /**< invalid inference information */
    261 PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
    262 PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
    263 PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
    265typedef enum Proprule PROPRULE;
    266
    267/** inference information */
    268struct InferInfo
    269{
    270 union
    271 {
    272 /** struct to use the inference information */
    273 struct
    274 {
    275 unsigned int proprule:2; /**< propagation rule that was applied */
    276 unsigned int data1:15; /**< data field one */
    277 unsigned int data2:15; /**< data field two */
    278 } asbits;
    279 int asint; /**< inference information as a single int value */
    280 } val;
    281};
    282typedef struct InferInfo INFERINFO;
    283
    284/** converts an integer into an inference information */
    285static
    287 int i /**< integer to convert */
    288 )
    289{
    290 INFERINFO inferinfo;
    291
    292 inferinfo.val.asint = i;
    293
    294 return inferinfo;
    295}
    296
    297/** converts an inference information into an int */
    298static
    300 INFERINFO inferinfo /**< inference information to convert */
    301 )
    302{
    303 return inferinfo.val.asint;
    304}
    305
    306/** rounds real to int and maps for large absolute values */
    307static
    309 SCIP* scip, /**< scip data structure */
    310 SCIP_Real real /**< double bound to convert */
    311 )
    312{
    313 int maxval;
    314
    316
    317 assert(maxval >= 0);
    318
    319 if( SCIPisInfinity(scip, real) || real > maxval )
    320 {
    321 return maxval;
    322 }
    323 if( SCIPisInfinity(scip, -real) || real < -maxval )
    324 {
    325 return -maxval;
    326 }
    328}
    329
    330/** returns the propagation rule stored in the inference information */
    331static
    333 INFERINFO inferinfo /**< inference information to convert */
    334 )
    335{
    336 return (PROPRULE) inferinfo.val.asbits.proprule;
    337}
    338
    339/** returns data field one of the inference information */
    340static
    342 INFERINFO inferinfo /**< inference information to convert */
    343 )
    344{
    345 return (int) inferinfo.val.asbits.data1;
    346}
    347
    348/** returns data field two of the inference information */
    349static
    351 INFERINFO inferinfo /**< inference information to convert */
    352 )
    353{
    354 return (int) inferinfo.val.asbits.data2;
    355}
    356
    357/** returns whether the inference information is valid */
    358static
    360 INFERINFO inferinfo /**< inference information to convert */
    361 )
    362{
    363 return (inferinfo.val.asint != 0);
    364}
    365
    366
    367/** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
    368static
    370 PROPRULE proprule, /**< propagation rule that deduced the value */
    371 int data1, /**< data field one */
    372 int data2 /**< data field two */
    373 )
    374{
    375 INFERINFO inferinfo;
    376
    377 /* check that the data members are in the range of the available bits */
    378 if( proprule == PROPRULE_0_INVALID || data1 < 0 || data1 >= (1<<15) || data2 < 0 || data2 >= (1<<15) )
    379 {
    380 inferinfo.val.asint = 0;
    381 assert(inferInfoGetProprule(inferinfo) == PROPRULE_0_INVALID);
    382 assert(inferInfoIsValid(inferinfo) == FALSE);
    383 }
    384 else
    385 {
    386 inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
    387 inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
    388 inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
    389 assert(inferInfoIsValid(inferinfo) == TRUE);
    390 }
    391
    392 return inferinfo;
    393}
    394
    395/**@} */
    396
    397/*
    398 * Local methods
    399 */
    400
    401/**@name Miscellaneous Methods
    402 *
    403 * @{
    404 */
    405
    406#ifndef NDEBUG
    407
    408/** compute the core of a job which lies in certain interval [begin, end) */
    409static
    411 int begin, /**< begin of the interval */
    412 int end, /**< end of the interval */
    413 int ect, /**< earliest completion time */
    414 int lst /**< latest start time */
    415 )
    416{
    417 int core;
    418
    419 core = MAX(0, MIN(end, ect) - MAX(lst, begin));
    420
    421 return core;
    422}
    423#else
    424#define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
    425#endif
    426
    427/** returns the implied earliest start time */ /*lint -e{715}*/
    428static
    430 SCIP* scip, /**< SCIP data structure */
    431 SCIP_VAR* var, /**< variable for which the implied est should be returned */
    432 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
    433 int* est /**< pointer to store the implied earliest start time */
    434 )
    435{ /*lint --e{715}*/
    436#ifdef SCIP_DISABLED_CODE
    437 /* there is a bug below */
    438 SCIP_VAR** vbdvars;
    439 SCIP_VAR* vbdvar;
    440 SCIP_Real* vbdcoefs;
    441 SCIP_Real* vbdconsts;
    442 void* image;
    443 int nvbdvars;
    444 int v;
    445#endif
    446
    448
    449#ifdef SCIP_DISABLED_CODE
    450 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
    451
    452 nvbdvars = SCIPvarGetNVlbs(var);
    453 vbdvars = SCIPvarGetVlbVars(var);
    454 vbdcoefs = SCIPvarGetVlbCoefs(var);
    455 vbdconsts = SCIPvarGetVlbConstants(var);
    456
    457 for( v = 0; v < nvbdvars; ++v )
    458 {
    459 vbdvar = vbdvars[v];
    460 assert(vbdvar != NULL);
    461
    462 image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
    463
    464 if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
    465 {
    466 int duration;
    467 int vbdconst;
    468
    469 duration = (int)(size_t)image;
    470 vbdconst = boundedConvertRealToInt(scip, vbdconsts[v]);
    471
    472 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
    474 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
    475
    476 if( duration >= vbdconst )
    477 {
    478 int impliedest;
    479
    480 impliedest = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
    481
    482 if( (*est) < impliedest )
    483 {
    484 (*est) = impliedest;
    485
    486 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
    487 }
    488 }
    489 }
    490 }
    491#endif
    492
    493 return SCIP_OKAY;
    494}
    495
    496/** returns the implied latest completion time */ /*lint -e{715}*/
    497static
    499 SCIP* scip, /**< SCIP data structure */
    500 SCIP_VAR* var, /**< variable for which the implied est should be returned */
    501 int duration, /**< duration of the given job */
    502 SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
    503 int* lct /**< pointer to store the implied latest completion time */
    504 )
    505{ /*lint --e{715}*/
    506#ifdef SCIP_DISABLED_CODE
    507 /* there is a bug below */
    508 SCIP_VAR** vbdvars;
    509 SCIP_VAR* vbdvar;
    510 SCIP_Real* vbdcoefs;
    511 SCIP_Real* vbdconsts;
    512 int nvbdvars;
    513 int v;
    514#endif
    515
    516 (*lct) = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
    517
    518#ifdef SCIP_DISABLED_CODE
    519 /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
    520
    521 nvbdvars = SCIPvarGetNVubs(var);
    522 vbdvars = SCIPvarGetVubVars(var);
    523 vbdcoefs = SCIPvarGetVubCoefs(var);
    524 vbdconsts = SCIPvarGetVubConstants(var);
    525
    526 for( v = 0; v < nvbdvars; ++v )
    527 {
    528 vbdvar = vbdvars[v];
    529 assert(vbdvar != NULL);
    530
    531 if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
    532 {
    533 int vbdconst;
    534
    535 vbdconst = boundedConvertRealToInt(scip, -vbdconsts[v]);
    536
    537 SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
    539 SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
    540
    541 if( duration >= -vbdconst )
    542 {
    543 int impliedlct;
    544
    545 impliedlct = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
    546
    547 if( (*lct) > impliedlct )
    548 {
    549 (*lct) = impliedlct;
    550
    551 SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
    552 }
    553 }
    554 }
    555 }
    556#endif
    557
    558 return SCIP_OKAY;
    559}
    560
    561/** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
    562static
    564 SCIP* scip, /**< SCIP data structure */
    565 SCIP_CONSDATA* consdata, /**< constraint data */
    566 SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
    567 int** coefs, /**< pointer to store the coefficients */
    568 int* nvars, /**< number if collect binary variables */
    569 int* startindices, /**< permutation with rspect to the start times */
    570 int curtime, /**< current point in time */
    571 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    572 int nfinished /**< number of jobs that finished before curtime or at curtime */
    573 )
    574{
    575 int nrowvars;
    576 int startindex;
    577 int size;
    578
    579 size = 10;
    580 nrowvars = 0;
    581 startindex = nstarted - 1;
    582
    583 SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
    584 SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
    585
    586 /* search for the (nstarted - nfinished) jobs which are active at curtime */
    587 while( nstarted - nfinished > nrowvars )
    588 {
    589 SCIP_VAR* var;
    590 int endtime;
    591 int duration;
    592 int demand;
    593 int varidx;
    594
    595 /* collect job information */
    596 varidx = startindices[startindex];
    597 assert(varidx >= 0 && varidx < consdata->nvars);
    598
    599 var = consdata->vars[varidx];
    600 duration = consdata->durations[varidx];
    601 demand = consdata->demands[varidx];
    602 assert(var != NULL);
    603
    604 endtime = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
    605
    606 /* check the end time of this job is larger than the curtime; in this case the job is still running */
    607 if( endtime > curtime )
    608 {
    609 SCIP_VAR** binvars;
    610 SCIP_Real* vals;
    611 int nbinvars;
    612 int start;
    613 int end;
    614 int b;
    615
    616 /* check if the linking constraints exists */
    617 assert(SCIPexistsConsLinking(scip, var));
    618 assert(SCIPgetConsLinking(scip, var) != NULL);
    619 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
    620
    621 /* collect linking constraint information */
    622 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
    623 vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
    624
    625 start = curtime - duration + 1;
    626 end = MIN(curtime, endtime - duration);
    627
    628 for( b = 0; b < nbinvars; ++b )
    629 {
    630 if( vals[b] < start )
    631 continue;
    632
    633 if( vals[b] > end )
    634 break;
    635
    636 assert(binvars[b] != NULL);
    637
    638 /* ensure array proper array size */
    639 if( size == *nvars )
    640 {
    641 size *= 2;
    642 SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
    643 SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
    644 }
    645
    646 (*vars)[*nvars] = binvars[b];
    647 (*coefs)[*nvars] = demand;
    648 (*nvars)++;
    649 }
    650 nrowvars++;
    651 }
    652
    653 startindex--;
    654 }
    655
    656 return SCIP_OKAY;
    657}
    658
    659/** collect all integer variable which belong to jobs which can run at the point of interest */
    660static
    662 SCIP* scip, /**< SCIP data structure */
    663 SCIP_CONSDATA* consdata, /**< constraint data */
    664 SCIP_VAR*** activevars, /**< jobs that are currently running */
    665 int* startindices, /**< permutation with rspect to the start times */
    666 int curtime, /**< current point in time */
    667 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    668 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    669 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
    670 int* lhs /**< lhs for the new row sum of lbs + minoffset */
    671 )
    672{
    673 SCIP_VAR* var;
    674 int startindex;
    675 int endtime;
    676 int duration;
    677 int starttime;
    678
    679 int varidx;
    680 int sumofstarts;
    681 int mindelta;
    682 int counter;
    683
    684 assert(curtime >= consdata->hmin);
    685 assert(curtime < consdata->hmax);
    686
    687 counter = 0;
    688 sumofstarts = 0;
    689
    690 mindelta = INT_MAX;
    691
    692 startindex = nstarted - 1;
    693
    694 /* search for the (nstarted - nfinished) jobs which are active at curtime */
    695 while( nstarted - nfinished > counter )
    696 {
    697 assert(startindex >= 0);
    698
    699 /* collect job information */
    700 varidx = startindices[startindex];
    701 assert(varidx >= 0 && varidx < consdata->nvars);
    702
    703 var = consdata->vars[varidx];
    704 duration = consdata->durations[varidx];
    705 assert(duration > 0);
    706 assert(var != NULL);
    707
    708 if( lower )
    710 else
    712
    713 endtime = MIN(starttime + duration, consdata->hmax);
    714
    715 /* check the end time of this job is larger than the curtime; in this case the job is still running */
    716 if( endtime > curtime )
    717 {
    718 (*activevars)[counter] = var;
    719 sumofstarts += starttime;
    720 mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
    721 counter++;
    722 }
    723
    724 startindex--;
    725 }
    726
    727 assert(mindelta > 0);
    728 *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
    729
    730 return SCIP_OKAY;
    731}
    732
    733/** initialize the sorted event point arrays */
    734static
    736 SCIP* scip, /**< SCIP data structure */
    737 int nvars, /**< number of start time variables (activities) */
    738 SCIP_VAR** vars, /**< array of start time variables */
    739 int* durations, /**< array of durations per start time variable */
    740 int* starttimes, /**< array to store sorted start events */
    741 int* endtimes, /**< array to store sorted end events */
    742 int* startindices, /**< permutation with rspect to the start times */
    743 int* endindices, /**< permutation with rspect to the end times */
    744 SCIP_Bool local /**< shall local bounds be used */
    745 )
    746{
    747 SCIP_VAR* var;
    748 int j;
    749
    750 assert(vars != NULL || nvars == 0);
    751
    752 /* assign variables, start and endpoints to arrays */
    753 for ( j = 0; j < nvars; ++j )
    754 {
    755 assert(vars != NULL);
    756
    757 var = vars[j];
    758 assert(var != NULL);
    759
    760 if( local )
    761 starttimes[j] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var));
    762 else
    763 starttimes[j] = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var));
    764
    765 startindices[j] = j;
    766
    767 if( local )
    768 endtimes[j] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
    769 else
    770 endtimes[j] = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
    771
    772 endindices[j] = j;
    773 }
    774
    775 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
    776 SCIPsortIntInt(starttimes, startindices, j);
    777 SCIPsortIntInt(endtimes, endindices, j);
    778}
    779
    780/** initialize the sorted event point arrays w.r.t. the given primal solutions */
    781static
    783 SCIP* scip, /**< SCIP data structure */
    784 SCIP_SOL* sol, /**< solution */
    785 int nvars, /**< number of start time variables (activities) */
    786 SCIP_VAR** vars, /**< array of start time variables */
    787 int* durations, /**< array of durations per start time variable */
    788 int* starttimes, /**< array to store sorted start events */
    789 int* endtimes, /**< array to store sorted end events */
    790 int* startindices, /**< permutation with rspect to the start times */
    791 int* endindices /**< permutation with rspect to the end times */
    792 )
    793{
    794 SCIP_VAR* var;
    795 int j;
    796
    797 assert(vars != NULL || nvars == 0);
    798
    799 /* assign variables, start and endpoints to arrays */
    800 for ( j = 0; j < nvars; ++j )
    801 {
    802 assert(vars != NULL);
    803
    804 var = vars[j];
    805 assert(var != NULL);
    806
    807 starttimes[j] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
    808 startindices[j] = j;
    809
    810 endtimes[j] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
    811 endindices[j] = j;
    812 }
    813
    814 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
    815 SCIPsortIntInt(starttimes, startindices, j);
    816 SCIPsortIntInt(endtimes, endindices, j);
    817}
    818
    819/** initialize the sorted event point arrays
    820 *
    821 * @todo Check the separation process!
    822 */
    823static
    825 SCIP* scip, /**< SCIP data structure */
    826 SCIP_CONSDATA* consdata, /**< constraint data */
    827 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    828 int* starttimes, /**< array to store sorted start events */
    829 int* endtimes, /**< array to store sorted end events */
    830 int* startindices, /**< permutation with rspect to the start times */
    831 int* endindices, /**< permutation with rspect to the end times */
    832 int* nvars, /**< number of variables that are integral */
    833 SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
    834 )
    835{
    836 SCIP_VAR* var;
    837 int tmpnvars;
    838 int j;
    839
    840 tmpnvars = consdata->nvars;
    841 *nvars = 0;
    842
    843 /* assign variables, start and endpoints to arrays */
    844 for ( j = 0; j < tmpnvars; ++j )
    845 {
    846 var = consdata->vars[j];
    847 assert(var != NULL);
    848 assert(consdata->durations[j] > 0);
    849 assert(consdata->demands[j] > 0);
    850
    851 if( lower )
    852 {
    853 /* only consider jobs that are at their lower or upper bound */
    854 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
    855 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
    856 continue;
    857
    858 starttimes[*nvars] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
    859 startindices[*nvars] = j;
    860
    861 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
    862 endindices[*nvars] = j;
    863
    864 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
    865 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
    866 consdata->durations[j],
    867 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
    868 consdata->demands[startindices[*nvars]]);
    869
    870 (*nvars)++;
    871 }
    872 else
    873 {
    874 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
    875 || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
    876 continue;
    877
    878 starttimes[*nvars] = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
    879 startindices[*nvars] = j;
    880
    881 endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
    882 endindices[*nvars] = j;
    883
    884 SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
    885 *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
    886 consdata->durations[j],
    887 starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
    888 consdata->demands[startindices[*nvars]]);
    889
    890 (*nvars)++;
    891 }
    892 }
    893
    894 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
    895 SCIPsortIntInt(starttimes, startindices, *nvars);
    896 SCIPsortIntInt(endtimes, endindices, *nvars);
    897
    898#ifdef SCIP_DEBUG
    899 SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
    900
    901 for ( j = 0; j < *nvars; ++j )
    902 {
    903 SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
    904 startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
    905 consdata->demands[startindices[j]]);
    906 }
    907
    908 for ( j = 0; j < *nvars; ++j )
    909 {
    910 SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
    911 consdata->demands[endindices[j]]);
    912 }
    913#endif
    914}
    915
    916#ifdef SCIP_STATISTIC
    917/** this method checks for relevant intervals for energetic reasoning */
    918static
    919SCIP_RETCODE computeRelevantEnergyIntervals(
    920 SCIP* scip, /**< SCIP data structure */
    921 int nvars, /**< number of start time variables (activities) */
    922 SCIP_VAR** vars, /**< array of start time variables */
    923 int* durations, /**< array of durations */
    924 int* demands, /**< array of demands */
    925 int capacity, /**< cumulative capacity */
    926 int hmin, /**< left bound of time axis to be considered (including hmin) */
    927 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    928 int** timepoints, /**< array to store relevant points in time */
    929 SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
    930 int* ntimepoints, /**< pointer to store the number of timepoints */
    931 int* maxdemand, /**< pointer to store maximum over all demands */
    932 SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
    933 )
    934{
    935 int* starttimes; /* stores when each job is starting */
    936 int* endtimes; /* stores when each job ends */
    937 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    938 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    939
    940 SCIP_Real totaldemand;
    941 int curtime; /* point in time which we are just checking */
    942 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    943
    944 int j;
    945
    946 assert( scip != NULL );
    947 assert(durations != NULL);
    948 assert(demands != NULL);
    949 assert(capacity >= 0);
    950
    951 /* if no activities are associated with this cumulative then this constraint is redundant */
    952 if( nvars == 0 )
    953 return SCIP_OKAY;
    954
    955 assert(vars != NULL);
    956
    957 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    958 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    959 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    960 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    961
    962 /* create event point arrays */
    963 createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
    964
    965 endindex = 0;
    966 totaldemand = 0.0;
    967
    968 *ntimepoints = 0;
    969 (*timepoints)[0] = starttimes[0];
    970 (*cumulativedemands)[0] = 0;
    971 *maxdemand = 0;
    972
    973 /* check each startpoint of a job whether the capacity is kept or not */
    974 for( j = 0; j < nvars; ++j )
    975 {
    976 int lct;
    977 int idx;
    978
    979 curtime = starttimes[j];
    980
    981 if( curtime >= hmax )
    982 break;
    983
    984 /* free all capacity usages of jobs the are no longer running */
    985 while( endindex < nvars && endtimes[endindex] <= curtime )
    986 {
    987 int est;
    988
    989 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
    990 {
    991 (*ntimepoints)++;
    992 (*timepoints)[*ntimepoints] = endtimes[endindex];
    993 (*cumulativedemands)[*ntimepoints] = 0;
    994 }
    995
    996 idx = endindices[endindex];
    998 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
    999 endindex++;
    1000
    1001 (*cumulativedemands)[*ntimepoints] = totaldemand;
    1002 }
    1003
    1004 idx = startindices[j];
    1005 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
    1006 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
    1007
    1008 if( (*timepoints)[*ntimepoints] < curtime )
    1009 {
    1010 (*ntimepoints)++;
    1011 (*timepoints)[*ntimepoints] = curtime;
    1012 (*cumulativedemands)[*ntimepoints] = 0;
    1013 }
    1014
    1015 (*cumulativedemands)[*ntimepoints] = totaldemand;
    1016
    1017 /* add the relative capacity requirements for all job which start at the curtime */
    1018 while( j+1 < nvars && starttimes[j+1] == curtime )
    1019 {
    1020 ++j;
    1021 idx = startindices[j];
    1022 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
    1023 totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
    1024
    1025 (*cumulativedemands)[*ntimepoints] = totaldemand;
    1026 }
    1027 } /*lint --e{850}*/
    1028
    1029 /* free all capacity usages of jobs that are no longer running */
    1030 while( endindex < nvars/* && endtimes[endindex] < hmax*/)
    1031 {
    1032 int est;
    1033 int idx;
    1034
    1035 if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
    1036 {
    1037 (*ntimepoints)++;
    1038 (*timepoints)[*ntimepoints] = endtimes[endindex];
    1039 (*cumulativedemands)[*ntimepoints] = 0;
    1040 }
    1041
    1042 idx = endindices[endindex];
    1044 totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
    1045 (*cumulativedemands)[*ntimepoints] = totaldemand;
    1046
    1047 ++endindex;
    1048 }
    1049
    1050 (*ntimepoints)++;
    1051 /* compute minimum free capacity */
    1052 (*minfreecapacity) = INT_MAX;
    1053 for( j = 0; j < *ntimepoints; ++j )
    1054 {
    1055 if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
    1056 *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
    1057 }
    1058
    1059 /* free buffer arrays */
    1060 SCIPfreeBufferArray(scip, &endindices);
    1061 SCIPfreeBufferArray(scip, &startindices);
    1062 SCIPfreeBufferArray(scip, &endtimes);
    1063 SCIPfreeBufferArray(scip, &starttimes);
    1064
    1065 return SCIP_OKAY;
    1066}
    1067
    1068/** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
    1069static
    1070SCIP_RETCODE evaluateCumulativeness(
    1071 SCIP* scip, /**< pointer to scip */
    1072 SCIP_CONS* cons /**< cumulative constraint */
    1073 )
    1074{
    1075 SCIP_CONSDATA* consdata;
    1076 int nvars;
    1077 int v;
    1078 int capacity;
    1079
    1080 /* output values: */
    1081 SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
    1082 SCIP_Real cumfactor1;
    1083 SCIP_Real resstrength1; /* overall strength */
    1084 SCIP_Real resstrength2; /* timepoint wise maximum */
    1085
    1086 /* helpful variables: */
    1087 SCIP_Real globalpeak;
    1088 SCIP_Real globalmaxdemand;
    1089
    1090 /* get constraint data structure */
    1091 consdata = SCIPconsGetData(cons);
    1092 assert(consdata != NULL);
    1093
    1094 nvars = consdata->nvars;
    1095 capacity = consdata->capacity;
    1096 globalpeak = 0.0;
    1097 globalmaxdemand = 0.0;
    1098
    1099 disjfactor2 = 0.0;
    1100 cumfactor1 = 0.0;
    1101 resstrength2 = 0.0;
    1102
    1103 /* check each starting time (==each job, but inefficient) */
    1104 for( v = 0; v < nvars; ++v )
    1105 {
    1106 SCIP_Real peak;
    1107 SCIP_Real maxdemand;
    1108 SCIP_Real deltademand;
    1109 int ndemands;
    1110 int nlarge;
    1111
    1112 int timepoint;
    1113 int j;
    1114 timepoint = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
    1115 peak = consdata->demands[v];
    1116 ndemands = 1;
    1117 maxdemand = 0;
    1118 nlarge = 0;
    1119
    1120 if( consdata->demands[v] > capacity / 3 )
    1121 nlarge++;
    1122
    1123 for( j = 0; j < nvars; ++j )
    1124 {
    1125 int lb;
    1126
    1127 if( j == v )
    1128 continue;
    1129
    1130 maxdemand = 0.0;
    1131 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
    1132
    1133 if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
    1134 {
    1135 peak += consdata->demands[j];
    1136 ndemands++;
    1137
    1138 if( consdata->demands[j] > consdata->capacity / 3 )
    1139 nlarge++;
    1140 }
    1141 }
    1142
    1143 deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
    1144 globalpeak = MAX(globalpeak, peak);
    1145 globalmaxdemand = MAX(globalmaxdemand, maxdemand);
    1146
    1147 if( peak > capacity )
    1148 {
    1149 disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
    1150 cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
    1151 resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
    1152 }
    1153 }
    1154
    1155 resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
    1156
    1157 consdata->maxpeak = boundedConvertRealToInt(scip, globalpeak);
    1158 consdata->disjfactor2 = disjfactor2;
    1159 consdata->cumfactor1 = cumfactor1;
    1160 consdata->resstrength2 = resstrength2;
    1161 consdata->resstrength1 = resstrength1;
    1162
    1163 /* get estimated res strength */
    1164 {
    1165 int* timepoints;
    1166 SCIP_Real* estimateddemands;
    1167 int ntimepoints;
    1168 int maxdemand;
    1169 SCIP_Real minfreecapacity;
    1170
    1171 SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
    1172 SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
    1173
    1174 ntimepoints = 0;
    1175 minfreecapacity = INT_MAX;
    1176
    1177 SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
    1178 consdata->durations, consdata->demands,
    1179 capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
    1180 &ntimepoints, &maxdemand, &minfreecapacity) );
    1181
    1182 /* free buffer arrays */
    1183 SCIPfreeBufferArray(scip, &estimateddemands);
    1184 SCIPfreeBufferArray(scip, &timepoints);
    1185
    1186 consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
    1187 }
    1188
    1189 SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
    1190 SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
    1191 consdata->estimatedstrength);
    1192
    1193 return SCIP_OKAY;
    1194}
    1195#endif
    1196
    1197/** gets the active variables together with the constant */
    1198static
    1200 SCIP* scip, /**< SCIP data structure */
    1201 SCIP_VAR** var, /**< pointer to store the active variable */
    1202 int* scalar, /**< pointer to store the scalar */
    1203 int* constant /**< pointer to store the constant */
    1204 )
    1205{
    1206 if( !SCIPvarIsActive(*var) )
    1207 {
    1208 SCIP_Real realscalar;
    1209 SCIP_Real realconstant;
    1210
    1211 realscalar = 1.0;
    1212 realconstant = 0.0;
    1213
    1215
    1216 /* transform variable to active variable */
    1217 SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
    1218 assert(!SCIPisZero(scip, realscalar));
    1219 assert(SCIPvarIsActive(*var));
    1220
    1221 if( realconstant < 0.0 )
    1222 (*constant) = -boundedConvertRealToInt(scip, -realconstant);
    1223 else
    1224 (*constant) = boundedConvertRealToInt(scip, realconstant);
    1225
    1226 if( realscalar < 0.0 )
    1227 (*scalar) = -boundedConvertRealToInt(scip, -realscalar);
    1228 else
    1229 (*scalar) = boundedConvertRealToInt(scip, realscalar);
    1230 }
    1231 else
    1232 {
    1233 (*scalar) = 1;
    1234 (*constant) = 0;
    1235 }
    1236
    1237 assert(*scalar != 0);
    1238
    1239 return SCIP_OKAY;
    1240}
    1241
    1242/** computes the total energy of all jobs */
    1243static
    1245 int* durations, /**< array of job durations */
    1246 int* demands, /**< array of job demands */
    1247 int njobs /**< number of jobs */
    1248 )
    1249{
    1250 SCIP_Longint energy;
    1251 int j;
    1252
    1253 energy = 0;
    1254
    1255 for( j = 0; j < njobs; ++j )
    1256 energy += (SCIP_Longint) durations[j] * demands[j];
    1257
    1258 return energy;
    1259}
    1260
    1261/**@} */
    1262
    1263/**@name Default method to solve a cumulative condition
    1264 *
    1265 * @{
    1266 */
    1267
    1268/** setup and solve subscip to solve single cumulative condition */
    1269static
    1271 SCIP* subscip, /**< subscip data structure */
    1272 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
    1273 int* durations, /**< array of durations */
    1274 int* demands, /**< array of demands */
    1275 int njobs, /**< number of jobs (activities) */
    1276 int capacity, /**< cumulative capacity */
    1277 int hmin, /**< left bound of time axis to be considered (including hmin) */
    1278 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    1279 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
    1280 SCIP_Real timelimit, /**< time limit for solving in seconds */
    1281 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
    1282 SCIP_Real* ests, /**< array of earliest start times for each job */
    1283 SCIP_Real* lsts, /**< array of latest start times for each job */
    1284 SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
    1285 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
    1286 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
    1287 SCIP_Bool* error /**< pointer to store if an error occurred */
    1288 )
    1289{
    1290 SCIP_VAR** subvars;
    1291 SCIP_CONS* cons;
    1292
    1293 char name[SCIP_MAXSTRLEN];
    1294 int v;
    1295 SCIP_RETCODE retcode;
    1296
    1297 assert(subscip != NULL);
    1298
    1299 /* copy all plugins */
    1301
    1302 /* create the subproblem */
    1303 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
    1304
    1305 SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
    1306
    1307 /* create for each job a start time variable */
    1308 for( v = 0; v < njobs; ++v )
    1309 {
    1310 SCIP_Real objval;
    1311
    1312 /* construct variable name */
    1313 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
    1314
    1315 if( objvals == NULL )
    1316 objval = 0.0;
    1317 else
    1318 objval = objvals[v];
    1319
    1320 SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
    1321 SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
    1322 }
    1323
    1324 /* create cumulative constraint */
    1325 SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
    1326 njobs, subvars, durations, demands, capacity) );
    1327
    1328 /* set effective horizon */
    1329 SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
    1330 SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
    1331
    1332 /* add cumulative constraint */
    1333 SCIP_CALL( SCIPaddCons(subscip, cons) );
    1334 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
    1335
    1336 /* set CP solver settings
    1337 *
    1338 * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
    1339 * time limit.
    1340 */
    1342
    1343 /* do not abort subproblem on CTRL-C */
    1344 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
    1345
    1346 /* disable output to console */
    1347 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
    1348
    1349 /* set limits for the subproblem */
    1350 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
    1351 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
    1352 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
    1353
    1354 /* forbid recursive call of heuristics and separators solving subMIPs */
    1355 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
    1356
    1357 /* solve single cumulative constraint by branch and bound */
    1358 retcode = SCIPsolve(subscip);
    1359
    1360 if( retcode != SCIP_OKAY )
    1361 (*error) = TRUE;
    1362 else
    1363 {
    1364 SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
    1365
    1366 /* evaluated solution status */
    1367 switch( SCIPgetStatus(subscip) )
    1368 {
    1371 (*infeasible) = TRUE;
    1372 (*solved) = TRUE;
    1373 break;
    1375 (*unbounded) = TRUE;
    1376 (*solved) = TRUE;
    1377 break;
    1379 {
    1380 SCIP_SOL* sol;
    1381 SCIP_Real solval;
    1382
    1383 sol = SCIPgetBestSol(subscip);
    1384 assert(sol != NULL);
    1385
    1386 for( v = 0; v < njobs; ++v )
    1387 {
    1388 solval = SCIPgetSolVal(subscip, sol, subvars[v]);
    1389
    1390 ests[v] = solval;
    1391 lsts[v] = solval;
    1392 }
    1393 (*solved) = TRUE;
    1394 break;
    1395 }
    1402 /* transfer the global bound changes */
    1403 for( v = 0; v < njobs; ++v )
    1404 {
    1405 ests[v] = SCIPvarGetLbGlobal(subvars[v]);
    1406 lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
    1407 }
    1408 (*solved) = FALSE;
    1409 break;
    1410
    1419 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
    1420 return SCIP_INVALIDDATA;
    1421 }
    1422 }
    1423
    1424 /* release all variables */
    1425 for( v = 0; v < njobs; ++v )
    1426 {
    1427 SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
    1428 }
    1429
    1430 SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
    1431
    1432 return SCIP_OKAY;
    1433}
    1434
    1435/** solve single cumulative condition using SCIP and a single cumulative constraint */
    1436static
    1437SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
    1438{
    1439 SCIP* subscip;
    1440
    1441 SCIP_RETCODE retcode;
    1442
    1443 assert(njobs > 0);
    1444
    1445 (*solved) = FALSE;
    1446 (*infeasible) = FALSE;
    1447 (*unbounded) = FALSE;
    1448 (*error) = FALSE;
    1449
    1450 SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
    1451
    1452 /* initialize the sub-problem */
    1453 SCIP_CALL( SCIPcreate(&subscip) );
    1454
    1455 /* create and solve the subproblem. catch possible errors */
    1456 retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
    1457 njobs, capacity, hmin, hmax,
    1458 maxnodes, timelimit, memorylimit,
    1459 ests, lsts,
    1460 infeasible, unbounded, solved, error);
    1461
    1462 /* free the subscip in any case */
    1463 SCIP_CALL( SCIPfree(&subscip) );
    1464
    1465 SCIP_CALL( retcode );
    1466
    1467 return SCIP_OKAY;
    1468}
    1469
    1470#ifdef SCIP_DISABLED_CODE
    1471/* The following code should work, but is currently not used. */
    1472
    1473/** solve single cumulative condition using SCIP and the time indexed formulation */
    1474static
    1475SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
    1476{
    1477 SCIP* subscip;
    1478 SCIP_VAR*** binvars;
    1479 SCIP_RETCODE retcode;
    1480 char name[SCIP_MAXSTRLEN];
    1481 int minest;
    1482 int maxlct;
    1483 int t;
    1484 int v;
    1485
    1486 assert(njobs > 0);
    1487
    1488 (*solved) = FALSE;
    1489 (*infeasible) = FALSE;
    1490 (*unbounded) = FALSE;
    1491 (*error) = FALSE;
    1492
    1493 SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
    1494
    1495 /* initialize the sub-problem */
    1496 SCIP_CALL( SCIPcreate(&subscip) );
    1497
    1498 /* copy all plugins */
    1500
    1501 /* create the subproblem */
    1502 SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
    1503
    1504 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
    1505
    1506 minest = INT_MAX;
    1507 maxlct = INT_MIN;
    1508
    1509 /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
    1510 * partitioning constrain which forces that job starts
    1511 */
    1512 for( v = 0; v < njobs; ++v )
    1513 {
    1514 SCIP_CONS* cons;
    1515 SCIP_Real objval;
    1516 int timeinterval;
    1517 int est;
    1518 int lst;
    1519
    1520 if( objvals == NULL )
    1521 objval = 0.0;
    1522 else
    1523 objval = objvals[v];
    1524
    1525 est = ests[v];
    1526 lst = lsts[v];
    1527
    1528 /* compute number of possible start points */
    1529 timeinterval = lst - est + 1;
    1530 assert(timeinterval > 0);
    1531
    1532 /* compute the smallest earliest start time and largest latest completion time */
    1533 minest = MIN(minest, est);
    1534 maxlct = MAX(maxlct, lst + durations[v]);
    1535
    1536 /* construct constraint name */
    1537 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
    1538
    1539 SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
    1540
    1541 SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
    1542
    1543 for( t = 0; t < timeinterval; ++t )
    1544 {
    1545 SCIP_VAR* binvar;
    1546
    1547 /* construct varibale name */
    1548 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
    1549
    1550 SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
    1551 SCIP_CALL( SCIPaddVar(subscip, binvar) );
    1552
    1553 /* add binary varibale to the set partitioning constraint which ensures that the job is started */
    1554 SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
    1555
    1556 binvars[v][t] = binvar;
    1557 }
    1558
    1559 /* add and release the set partitioning constraint */
    1560 SCIP_CALL( SCIPaddCons(subscip, cons) );
    1561 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
    1562 }
    1563
    1564 /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
    1565 hmin = MAX(hmin, minest);
    1566 hmax = MIN(hmax, maxlct);
    1567 assert(hmin > INT_MIN);
    1568 assert(hmax < INT_MAX);
    1569 assert(hmin < hmax);
    1570
    1571 /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
    1572 for( t = hmin; t < hmax; ++t )
    1573 {
    1574 SCIP_CONS* cons;
    1575
    1576 /* construct constraint name */
    1577 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
    1578
    1579 /* create an empty knapsack constraint */
    1580 SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
    1581
    1582 /* add all jobs which potentially can be processed at that time point */
    1583 for( v = 0; v < njobs; ++v )
    1584 {
    1585 int duration;
    1586 int demand;
    1587 int start;
    1588 int end;
    1589 int est;
    1590 int lst;
    1591 int k;
    1592
    1593 est = ests[v];
    1594 lst = lsts[v] ;
    1595
    1596 duration = durations[v];
    1597 assert(duration > 0);
    1598
    1599 /* check if the varibale is processed potentially at time point t */
    1600 if( t < est || t >= lst + duration )
    1601 continue;
    1602
    1603 demand = demands[v];
    1604 assert(demand >= 0);
    1605
    1606 start = MAX(t - duration + 1, est);
    1607 end = MIN(t, lst);
    1608
    1609 assert(start <= end);
    1610
    1611 for( k = start; k <= end; ++k )
    1612 {
    1613 assert(binvars[v][k] != NULL);
    1614 SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
    1615 }
    1616 }
    1617
    1618 /* add and release the knapsack constraint */
    1619 SCIP_CALL( SCIPaddCons(subscip, cons) );
    1620 SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
    1621 }
    1622
    1623 /* do not abort subproblem on CTRL-C */
    1624 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
    1625
    1626 /* disable output to console */
    1627 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
    1628
    1629 /* set limits for the subproblem */
    1630 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
    1631 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
    1632 SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
    1633
    1634 /* solve single cumulative constraint by branch and bound */
    1635 retcode = SCIPsolve(subscip);
    1636
    1637 if( retcode != SCIP_OKAY )
    1638 (*error) = TRUE;
    1639 else
    1640 {
    1641 SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
    1642
    1643 /* evaluated solution status */
    1644 switch( SCIPgetStatus(subscip) )
    1645 {
    1648 (*infeasible) = TRUE;
    1649 (*solved) = TRUE;
    1650 break;
    1652 (*unbounded) = TRUE;
    1653 (*solved) = TRUE;
    1654 break;
    1656 {
    1657 SCIP_SOL* sol;
    1658
    1659 sol = SCIPgetBestSol(subscip);
    1660 assert(sol != NULL);
    1661
    1662 for( v = 0; v < njobs; ++v )
    1663 {
    1664 int timeinterval;
    1665 int est;
    1666 int lst;
    1667
    1668 est = ests[v];
    1669 lst = lsts[v];
    1670
    1671 /* compute number of possible start points */
    1672 timeinterval = lst - est + 1;
    1673
    1674 /* check which binary varibale is set to one */
    1675 for( t = 0; t < timeinterval; ++t )
    1676 {
    1677 if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
    1678 {
    1679 ests[v] = est + t;
    1680 lsts[v] = est + t;
    1681 break;
    1682 }
    1683 }
    1684 }
    1685
    1686 (*solved) = TRUE;
    1687 break;
    1688 }
    1694 /* transfer the global bound changes */
    1695 for( v = 0; v < njobs; ++v )
    1696 {
    1697 int timeinterval;
    1698 int est;
    1699 int lst;
    1700
    1701 est = ests[v];
    1702 lst = lsts[v];
    1703
    1704 /* compute number of possible start points */
    1705 timeinterval = lst - est + 1;
    1706
    1707 /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
    1708 for( t = 0; t < timeinterval; ++t )
    1709 {
    1710 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
    1711 {
    1712 ests[v] = est + t;
    1713 break;
    1714 }
    1715 }
    1716
    1717 /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
    1718 for( t = timeinterval - 1; t >= 0; --t )
    1719 {
    1720 if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
    1721 {
    1722 lsts[v] = est + t;
    1723 break;
    1724 }
    1725 }
    1726 }
    1727 (*solved) = FALSE;
    1728 break;
    1729
    1735 SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
    1736 return SCIP_INVALIDDATA;
    1737 }
    1738 }
    1739
    1740 /* release all variables */
    1741 for( v = 0; v < njobs; ++v )
    1742 {
    1743 int timeinterval;
    1744 int est;
    1745 int lst;
    1746
    1747 est = ests[v];
    1748 lst = lsts[v];
    1749
    1750 /* compute number of possible start points */
    1751 timeinterval = lst - est + 1;
    1752
    1753 for( t = 0; t < timeinterval; ++t )
    1754 {
    1755 SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
    1756 }
    1757 SCIPfreeBufferArray(subscip, &binvars[v]);
    1758 }
    1759
    1760 SCIPfreeBufferArray(subscip, &binvars);
    1761
    1762 SCIP_CALL( SCIPfree(&subscip) );
    1763
    1764 return SCIP_OKAY;
    1765}
    1766#endif
    1767
    1768/**@} */
    1769
    1770/**@name Constraint handler data
    1771 *
    1772 * Method used to create and free the constraint handler data when including and removing the cumulative constraint
    1773 * handler.
    1774 *
    1775 * @{
    1776 */
    1777
    1778/** creates constaint handler data for cumulative constraint handler */
    1779static
    1781 SCIP* scip, /**< SCIP data structure */
    1782 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
    1783 SCIP_EVENTHDLR* eventhdlr /**< event handler */
    1784 )
    1785{
    1786 /* create precedence constraint handler data */
    1787 assert(scip != NULL);
    1788 assert(conshdlrdata != NULL);
    1789 assert(eventhdlr != NULL);
    1790
    1791 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
    1792
    1793 /* set event handler for checking if bounds of start time variables are tighten */
    1794 (*conshdlrdata)->eventhdlr = eventhdlr;
    1795
    1796 /* set default methed for solving single cumulative conditions using SCIP and a CP model */
    1797 (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
    1798
    1799#ifdef SCIP_STATISTIC
    1800 (*conshdlrdata)->nlbtimetable = 0;
    1801 (*conshdlrdata)->nubtimetable = 0;
    1802 (*conshdlrdata)->ncutofftimetable = 0;
    1803 (*conshdlrdata)->nlbedgefinder = 0;
    1804 (*conshdlrdata)->nubedgefinder = 0;
    1805 (*conshdlrdata)->ncutoffedgefinder = 0;
    1806 (*conshdlrdata)->ncutoffoverload = 0;
    1807 (*conshdlrdata)->ncutoffoverloadTTEF = 0;
    1808
    1809 (*conshdlrdata)->nirrelevantjobs = 0;
    1810 (*conshdlrdata)->nalwaysruns = 0;
    1811 (*conshdlrdata)->nremovedlocks = 0;
    1812 (*conshdlrdata)->ndualfixs = 0;
    1813 (*conshdlrdata)->ndecomps = 0;
    1814 (*conshdlrdata)->ndualbranchs = 0;
    1815 (*conshdlrdata)->nallconsdualfixs = 0;
    1816 (*conshdlrdata)->naddedvarbounds = 0;
    1817 (*conshdlrdata)->naddeddisjunctives = 0;
    1818#endif
    1819
    1820 return SCIP_OKAY;
    1821}
    1822
    1823/** frees constraint handler data for logic or constraint handler */
    1824static
    1826 SCIP* scip, /**< SCIP data structure */
    1827 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
    1828 )
    1829{
    1830 assert(conshdlrdata != NULL);
    1831 assert(*conshdlrdata != NULL);
    1832
    1833 SCIPfreeBlockMemory(scip, conshdlrdata);
    1834}
    1835
    1836/**@} */
    1837
    1838
    1839/**@name Constraint data methods
    1840 *
    1841 * @{
    1842 */
    1843
    1844/** catches bound change events for all variables in transformed cumulative constraint */
    1845static
    1847 SCIP* scip, /**< SCIP data structure */
    1848 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
    1849 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    1850 )
    1851{
    1852 int v;
    1853
    1854 assert(scip != NULL);
    1855 assert(consdata != NULL);
    1856 assert(eventhdlr != NULL);
    1857
    1858 /* catch event for every single variable */
    1859 for( v = 0; v < consdata->nvars; ++v )
    1860 {
    1861 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
    1862 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
    1863 }
    1864
    1865 return SCIP_OKAY;
    1866}
    1867
    1868/** drops events for variable at given position */
    1869static
    1871 SCIP* scip, /**< SCIP data structure */
    1872 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
    1873 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
    1874 int pos /**< array position of variable to catch bound change events for */
    1875 )
    1876{
    1877 assert(scip != NULL);
    1878 assert(consdata != NULL);
    1879 assert(eventhdlr != NULL);
    1880 assert(0 <= pos && pos < consdata->nvars);
    1881 assert(consdata->vars[pos] != NULL);
    1882
    1883 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
    1884 SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
    1885
    1886 return SCIP_OKAY;
    1887}
    1888
    1889/** drops bound change events for all variables in transformed linear constraint */
    1890static
    1892 SCIP* scip, /**< SCIP data structure */
    1893 SCIP_CONSDATA* consdata, /**< linear constraint data */
    1894 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    1895 )
    1896{
    1897 int v;
    1898
    1899 assert(scip != NULL);
    1900 assert(consdata != NULL);
    1901
    1902 /* drop event of every single variable */
    1903 for( v = 0; v < consdata->nvars; ++v )
    1904 {
    1905 SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
    1906 }
    1907
    1908 return SCIP_OKAY;
    1909}
    1910
    1911/** initialize variable lock data structure */
    1912static
    1914 SCIP_CONSDATA* consdata, /**< constraint data */
    1915 SCIP_Bool locked /**< should the variable be locked? */
    1916 )
    1917{
    1918 int nvars;
    1919 int v;
    1920
    1921 nvars = consdata->nvars;
    1922
    1923 /* initialize locking arrays */
    1924 for( v = 0; v < nvars; ++v )
    1925 {
    1926 consdata->downlocks[v] = locked;
    1927 consdata->uplocks[v] = locked;
    1928 }
    1929}
    1930
    1931/** creates constraint data of cumulative constraint */
    1932static
    1934 SCIP* scip, /**< SCIP data structure */
    1935 SCIP_CONSDATA** consdata, /**< pointer to consdata */
    1936 SCIP_VAR** vars, /**< array of integer variables */
    1937 SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
    1938 int* durations, /**< array containing corresponding durations */
    1939 int* demands, /**< array containing corresponding demands */
    1940 int nvars, /**< number of variables */
    1941 int capacity, /**< available cumulative capacity */
    1942 int hmin, /**< left bound of time axis to be considered (including hmin) */
    1943 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    1944 SCIP_Bool check /**< is the corresponding constraint a check constraint */
    1945 )
    1946{
    1947 int v;
    1948
    1949 assert(scip != NULL);
    1950 assert(consdata != NULL);
    1951 assert(vars != NULL || nvars > 0);
    1952 assert(demands != NULL);
    1953 assert(durations != NULL);
    1954 assert(capacity >= 0);
    1955 assert(hmin >= 0);
    1956 assert(hmin < hmax);
    1957
    1958 /* create constraint data */
    1959 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
    1960
    1961 (*consdata)->hmin = hmin;
    1962 (*consdata)->hmax = hmax;
    1963
    1964 (*consdata)->capacity = capacity;
    1965 (*consdata)->demandrows = NULL;
    1966 (*consdata)->demandrowssize = 0;
    1967 (*consdata)->ndemandrows = 0;
    1968 (*consdata)->scoverrows = NULL;
    1969 (*consdata)->nscoverrows = 0;
    1970 (*consdata)->scoverrowssize = 0;
    1971 (*consdata)->bcoverrows = NULL;
    1972 (*consdata)->nbcoverrows = 0;
    1973 (*consdata)->bcoverrowssize = 0;
    1974 (*consdata)->nvars = nvars;
    1975 (*consdata)->varssize = nvars;
    1976 (*consdata)->signature = 0;
    1977 (*consdata)->validsignature = FALSE;
    1978 (*consdata)->normalized = FALSE;
    1979 (*consdata)->covercuts = FALSE;
    1980 (*consdata)->propagated = FALSE;
    1981 (*consdata)->varbounds = FALSE;
    1982 (*consdata)->triedsolving = FALSE;
    1983
    1984 if( nvars > 0 )
    1985 {
    1986 assert(vars != NULL); /* for flexelint */
    1987
    1988 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
    1989 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
    1990 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
    1991 (*consdata)->linkingconss = NULL;
    1992
    1993 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
    1994 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
    1995
    1996 /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
    1997 initializeLocks(*consdata, check);
    1998
    1999 if( linkingconss != NULL )
    2000 {
    2001 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
    2002 }
    2003
    2004 /* transform variables, if they are not yet transformed */
    2005 if( SCIPisTransformed(scip) )
    2006 {
    2007 SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
    2008
    2009 /* get transformed variables and do NOT captures these */
    2010 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
    2011
    2012 /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
    2013 * been multi-aggregated
    2014 */
    2015 for( v = 0; v < nvars; ++v )
    2016 {
    2017 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
    2018 }
    2019
    2020 if( linkingconss != NULL )
    2021 {
    2022 /* get transformed constraints and captures these */
    2023 SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
    2024
    2025 for( v = 0; v < nvars; ++v )
    2026 assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
    2027 }
    2028 }
    2029
    2030#ifndef NDEBUG
    2031 /* only binary and integer variables can be used in cumulative constraints
    2032 * for fractional variable values, the constraint cannot be checked
    2033 */
    2034 for( v = 0; v < (*consdata)->nvars; ++v )
    2035 assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
    2036#endif
    2037 }
    2038 else
    2039 {
    2040 (*consdata)->vars = NULL;
    2041 (*consdata)->downlocks = NULL;
    2042 (*consdata)->uplocks = NULL;
    2043 (*consdata)->demands = NULL;
    2044 (*consdata)->durations = NULL;
    2045 (*consdata)->linkingconss = NULL;
    2046 }
    2047
    2048 /* initialize values for running propagation algorithms efficiently */
    2049 (*consdata)->resstrength1 = -1.0;
    2050 (*consdata)->resstrength2 = -1.0;
    2051 (*consdata)->cumfactor1 = -1.0;
    2052 (*consdata)->disjfactor1 = -1.0;
    2053 (*consdata)->disjfactor2 = -1.0;
    2054 (*consdata)->estimatedstrength = -1.0;
    2055
    2056 SCIPstatistic( (*consdata)->maxpeak = -1 );
    2057
    2058 return SCIP_OKAY;
    2059}
    2060
    2061/** releases LP rows of constraint data and frees rows array */
    2062static
    2064 SCIP* scip, /**< SCIP data structure */
    2065 SCIP_CONSDATA** consdata /**< constraint data */
    2066 )
    2067{
    2068 int r;
    2069
    2070 assert(consdata != NULL);
    2071 assert(*consdata != NULL);
    2072
    2073 for( r = 0; r < (*consdata)->ndemandrows; ++r )
    2074 {
    2075 assert((*consdata)->demandrows[r] != NULL);
    2076 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
    2077 }
    2078
    2079 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
    2080
    2081 (*consdata)->ndemandrows = 0;
    2082 (*consdata)->demandrowssize = 0;
    2083
    2084 /* free rows of cover cuts */
    2085 for( r = 0; r < (*consdata)->nscoverrows; ++r )
    2086 {
    2087 assert((*consdata)->scoverrows[r] != NULL);
    2088 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
    2089 }
    2090
    2091 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
    2092
    2093 (*consdata)->nscoverrows = 0;
    2094 (*consdata)->scoverrowssize = 0;
    2095
    2096 for( r = 0; r < (*consdata)->nbcoverrows; ++r )
    2097 {
    2098 assert((*consdata)->bcoverrows[r] != NULL);
    2099 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
    2100 }
    2101
    2102 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
    2103
    2104 (*consdata)->nbcoverrows = 0;
    2105 (*consdata)->bcoverrowssize = 0;
    2106
    2107 (*consdata)->covercuts = FALSE;
    2108
    2109 return SCIP_OKAY;
    2110}
    2111
    2112/** frees a cumulative constraint data */
    2113static
    2115 SCIP* scip, /**< SCIP data structure */
    2116 SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
    2117 )
    2118{
    2119 int varssize;
    2120 int nvars;
    2121
    2122 assert(consdata != NULL);
    2123 assert(*consdata != NULL);
    2124
    2125 nvars = (*consdata)->nvars;
    2126 varssize = (*consdata)->varssize;
    2127
    2128 if( varssize > 0 )
    2129 {
    2130 int v;
    2131
    2132 /* release and free the rows */
    2133 SCIP_CALL( consdataFreeRows(scip, consdata) );
    2134
    2135 /* release the linking constraints if they were generated */
    2136 if( (*consdata)->linkingconss != NULL )
    2137 {
    2138 for( v = nvars-1; v >= 0; --v )
    2139 {
    2140 assert((*consdata)->linkingconss[v] != NULL );
    2141 SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
    2142 }
    2143
    2144 SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
    2145 }
    2146
    2147 /* free arrays */
    2148 SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
    2149 SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
    2150 SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
    2151 SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
    2152 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
    2153 }
    2154
    2155 /* free memory */
    2156 SCIPfreeBlockMemory(scip, consdata);
    2157
    2158 return SCIP_OKAY;
    2159}
    2160
    2161/** prints cumulative constraint to file stream */
    2162static
    2164 SCIP* scip, /**< SCIP data structure */
    2165 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
    2166 FILE* file /**< output file (or NULL for standard output) */
    2167 )
    2168{
    2169 int v;
    2170
    2171 assert(consdata != NULL);
    2172
    2173 /* print coefficients */
    2174 SCIPinfoMessage( scip, file, "cumulative(");
    2175
    2176 for( v = 0; v < consdata->nvars; ++v )
    2177 {
    2178 assert(consdata->vars[v] != NULL);
    2179 if( v > 0 )
    2180 SCIPinfoMessage(scip, file, ", ");
    2181 SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
    2182 SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
    2183 consdata->durations[v], consdata->demands[v]);
    2184 }
    2185 SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
    2186}
    2187
    2188/** deletes coefficient at given position from constraint data */
    2189static
    2191 SCIP* scip, /**< SCIP data structure */
    2192 SCIP_CONSDATA* consdata, /**< cumulative constraint data */
    2193 SCIP_CONS* cons, /**< knapsack constraint */
    2194 int pos /**< position of coefficient to delete */
    2195 )
    2196{
    2197 SCIP_CONSHDLR* conshdlr;
    2198 SCIP_CONSHDLRDATA* conshdlrdata;
    2199
    2200 assert(scip != NULL);
    2201 assert(consdata != NULL);
    2202 assert(cons != NULL);
    2203 assert(SCIPconsIsTransformed(cons));
    2204 assert(!SCIPinProbing(scip));
    2205
    2206 SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
    2207 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
    2208
    2209 /* remove the rounding locks for the deleted variable */
    2210 SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
    2211
    2212 consdata->downlocks[pos] = FALSE;
    2213 consdata->uplocks[pos] = FALSE;
    2214
    2215 if( consdata->linkingconss != NULL )
    2216 {
    2217 SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
    2218 }
    2219
    2220 /* get event handler */
    2221 conshdlr = SCIPconsGetHdlr(cons);
    2222 assert(conshdlr != NULL);
    2223 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2224 assert(conshdlrdata != NULL);
    2225 assert(conshdlrdata->eventhdlr != NULL);
    2226
    2227 /* drop events */
    2228 SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
    2229
    2230 SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
    2231 SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
    2232
    2233 /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
    2234 * position
    2235 */
    2236 if( pos != consdata->nvars - 1 )
    2237 {
    2238 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
    2239 consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
    2240 consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
    2241 consdata->demands[pos] = consdata->demands[consdata->nvars-1];
    2242 consdata->durations[pos] = consdata->durations[consdata->nvars-1];
    2243
    2244 if( consdata->linkingconss != NULL )
    2245 {
    2246 consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
    2247 }
    2248 }
    2249
    2250 consdata->nvars--;
    2251 consdata->validsignature = FALSE;
    2252 consdata->normalized = FALSE;
    2253
    2254 return SCIP_OKAY;
    2255}
    2256
    2257/** collect linking constraints for each integer variable */
    2258static
    2260 SCIP* scip, /**< SCIP data structure */
    2261 SCIP_CONSDATA* consdata /**< pointer to consdata */
    2262 )
    2263{
    2264 int nvars;
    2265 int v;
    2266
    2267 assert(scip != NULL);
    2268 assert(consdata != NULL);
    2269
    2270 nvars = consdata->nvars;
    2271 assert(nvars > 0);
    2272 assert(consdata->linkingconss == NULL);
    2273
    2274 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
    2275
    2276 for( v = 0; v < nvars; ++v )
    2277 {
    2278 SCIP_CONS* cons;
    2279 SCIP_VAR* var;
    2280
    2281 var = consdata->vars[v];
    2282 assert(var != NULL);
    2283
    2284 SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
    2285
    2286 /* create linking constraint if it does not exist yet */
    2287 if( !SCIPexistsConsLinking(scip, var) )
    2288 {
    2289 char name[SCIP_MAXSTRLEN];
    2290
    2291 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
    2292
    2293 /* creates and captures an linking constraint */
    2294 SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
    2295 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
    2296 SCIP_CALL( SCIPaddCons(scip, cons) );
    2297 consdata->linkingconss[v] = cons;
    2298 }
    2299 else
    2300 {
    2301 consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
    2302 SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
    2303 }
    2304
    2305 assert(SCIPexistsConsLinking(scip, var));
    2306 assert(consdata->linkingconss[v] != NULL);
    2307 assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
    2308
    2309 SCIP_STRINGEQ( SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking", SCIP_INVALIDCALL );
    2310 }
    2311
    2312 return SCIP_OKAY;
    2313}
    2314
    2315/**@} */
    2316
    2317
    2318/**@name Check methods
    2319 *
    2320 * @{
    2321 */
    2322
    2323/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
    2324 * given solution is satisfied
    2325 */
    2326static
    2328 SCIP* scip, /**< SCIP data structure */
    2329 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    2330 int nvars, /**< number of variables (jobs) */
    2331 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    2332 int* durations, /**< array containing corresponding durations */
    2333 int* demands, /**< array containing corresponding demands */
    2334 int capacity, /**< available cumulative capacity */
    2335 int hmin, /**< left bound of time axis to be considered (including hmin) */
    2336 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    2337 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
    2338 SCIP_CONS* cons, /**< constraint which is checked */
    2339 SCIP_Bool printreason /**< should the reason for the violation be printed? */
    2340 )
    2341{
    2342 int* startsolvalues; /* stores when each job is starting */
    2343 int* endsolvalues; /* stores when each job ends */
    2344 int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
    2345 int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
    2346
    2347 int freecapacity;
    2348 int curtime; /* point in time which we are just checking */
    2349 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    2350 int j;
    2351
    2352 SCIP_Real absviol;
    2353 SCIP_Real relviol;
    2354
    2355 assert(scip != NULL);
    2356 assert(violated != NULL);
    2357
    2358 (*violated) = FALSE;
    2359
    2360 if( nvars == 0 )
    2361 return SCIP_OKAY;
    2362
    2363 assert(vars != NULL);
    2364 assert(demands != NULL);
    2365 assert(durations != NULL);
    2366
    2367 /* compute time points where we have to check whether capacity constraint is infeasible or not */
    2368 SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
    2369 SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
    2370 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    2371 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    2372
    2373 /* assign variables, start and endpoints to arrays */
    2374 for ( j = 0; j < nvars; ++j )
    2375 {
    2376 int solvalue;
    2377
    2378 /* the constraint of the cumulative constraint handler should be called after the integrality check */
    2379 assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
    2380
    2381 solvalue = boundedConvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
    2382
    2383 /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
    2384 * jobs which start before hmin to hmin
    2385 */
    2386 startsolvalues[j] = MAX(solvalue, hmin);
    2387 startindices[j] = j;
    2388
    2389 endsolvalues[j] = MAX(solvalue + durations[j], hmin);
    2390 endindices[j] = j;
    2391 }
    2392
    2393 /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
    2394 * corresponding indices in the same way)
    2395 */
    2396 SCIPsortIntInt(startsolvalues, startindices, nvars);
    2397 SCIPsortIntInt(endsolvalues, endindices, nvars);
    2398
    2399 endindex = 0;
    2400 freecapacity = capacity;
    2401 absviol = 0.0;
    2402 relviol = 0.0;
    2403
    2404 /* check each start point of a job whether the capacity is kept or not */
    2405 for( j = 0; j < nvars; ++j )
    2406 {
    2407 /* only check intervals [hmin,hmax) */
    2408 curtime = startsolvalues[j];
    2409
    2410 if( curtime >= hmax )
    2411 break;
    2412
    2413 /* subtract all capacity needed up to this point */
    2414 freecapacity -= demands[startindices[j]];
    2415 while( j+1 < nvars && startsolvalues[j+1] == curtime )
    2416 {
    2417 j++;
    2418 freecapacity -= demands[startindices[j]];
    2419 }
    2420
    2421 /* free all capacity usages of jobs that are no longer running */
    2422 while( endindex < nvars && curtime >= endsolvalues[endindex] )
    2423 {
    2424 freecapacity += demands[endindices[endindex]];
    2425 ++endindex;
    2426 }
    2427 assert(freecapacity <= capacity);
    2428
    2429 /* update absolute and relative violation */
    2430 if( absviol < (SCIP_Real) (-freecapacity) )
    2431 {
    2432 absviol = -freecapacity;
    2433 relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
    2434 }
    2435
    2436 /* check freecapacity to be smaller than zero */
    2437 if( freecapacity < 0 && curtime >= hmin )
    2438 {
    2439 SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
    2440 (*violated) = TRUE;
    2441
    2442 if( printreason )
    2443 {
    2444 int i;
    2445
    2446 /* first state the violated constraints */
    2447 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    2448
    2449 /* second state the reason */
    2451 ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
    2452 curtime, capacity, capacity - freecapacity);
    2453
    2454 for( i = 0; i <= j; ++i )
    2455 {
    2456 if( startsolvalues[i] + durations[startindices[i]] > curtime )
    2457 {
    2458 SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
    2459 SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
    2460 demands[startindices[i]]);
    2461 }
    2462 }
    2463 }
    2464 break;
    2465 }
    2466 } /*lint --e{850}*/
    2467
    2468 /* update constraint violation in solution */
    2469 if( sol != NULL )
    2470 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
    2471
    2472 /* free all buffer arrays */
    2473 SCIPfreeBufferArray(scip, &endindices);
    2474 SCIPfreeBufferArray(scip, &startindices);
    2475 SCIPfreeBufferArray(scip, &endsolvalues);
    2476 SCIPfreeBufferArray(scip, &startsolvalues);
    2477
    2478 return SCIP_OKAY;
    2479}
    2480
    2481/** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
    2482 * least zero or not. If not (*violated) is set to TRUE
    2483 */
    2484static
    2486 SCIP* scip, /**< SCIP data structure */
    2487 SCIP_CONS* cons, /**< constraint to be checked */
    2488 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    2489 SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
    2490 SCIP_Bool printreason /**< should the reason for the violation be printed? */
    2491 )
    2492{
    2493 SCIP_CONSDATA* consdata;
    2494
    2495 assert(scip != NULL);
    2496 assert(cons != NULL);
    2497 assert(violated != NULL);
    2498
    2499 SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
    2500
    2501 consdata = SCIPconsGetData(cons);
    2502 assert(consdata != NULL);
    2503
    2504 /* check the cumulative condition */
    2505 SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
    2506 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
    2507 violated, cons, printreason) );
    2508
    2509 return SCIP_OKAY;
    2510}
    2511
    2512/**@} */
    2513
    2514/**@name Conflict analysis
    2515 *
    2516 * @{
    2517 */
    2518
    2519/** resolves the propagation of the core time algorithm */
    2520static
    2522 SCIP* scip, /**< SCIP data structure */
    2523 int nvars, /**< number of start time variables (activities) */
    2524 SCIP_VAR** vars, /**< array of start time variables */
    2525 int* durations, /**< array of durations */
    2526 int* demands, /**< array of demands */
    2527 int capacity, /**< cumulative capacity */
    2528 int hmin, /**< left bound of time axis to be considered (including hmin) */
    2529 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    2530 SCIP_VAR* infervar, /**< inference variable */
    2531 int inferdemand, /**< demand of the inference variable */
    2532 int inferpeak, /**< time point which causes the propagation */
    2533 int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
    2534 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
    2535 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    2536 int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
    2537 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    2538 )
    2539{
    2540 SCIP_VAR* var;
    2541 SCIP_Bool* reported;
    2542 int duration;
    2543 int maxlst;
    2544 int minect;
    2545 int ect;
    2546 int lst;
    2547 int j;
    2548
    2550
    2551 SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
    2552 SCIPvarGetName(infervar), inferdemand, inferpeak);
    2553 assert(nvars > 0);
    2554
    2555 /* adjusted capacity */
    2556 capacity -= inferdemand;
    2557 maxlst = INT_MIN;
    2558 minect = INT_MAX;
    2559
    2560 SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
    2561 BMSclearMemoryArray(reported, nvars);
    2562
    2563 /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
    2564 * inference peak and those where the current conflict bounds provide a core at the inference peak
    2565 */
    2566 for( j = 0; j < nvars && capacity >= 0; ++j )
    2567 {
    2568 var = vars[j];
    2569 assert(var != NULL);
    2570
    2571 /* skip inference variable */
    2572 if( var == infervar )
    2573 continue;
    2574
    2575 duration = durations[j];
    2576 assert(duration > 0);
    2577
    2578 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
    2579 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
    2580 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
    2581 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
    2582 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
    2583
    2584 SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
    2586 SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
    2587
    2588 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
    2590
    2591 /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
    2592 * that job without adding it the explanation
    2593 */
    2594 if( inferpeak < ect && lst <= inferpeak )
    2595 {
    2596 capacity -= demands[j];
    2597 reported[j] = TRUE;
    2598
    2599 maxlst = MAX(maxlst, lst);
    2600 minect = MIN(minect, ect);
    2601 assert(maxlst < minect);
    2602
    2603 if( explanation != NULL )
    2604 explanation[j] = TRUE;
    2605
    2606 continue;
    2607 }
    2608
    2609 /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
    2610 * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
    2611 * not part of the conflict yet we get the global bounds back.
    2612 */
    2613 ect = boundedConvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
    2615
    2616 /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
    2617 * of that job without and collect the job as part of the explanation
    2618 *
    2619 * @note we do not need to reported that job to SCIP since the required bounds are already reported
    2620 */
    2621 if( inferpeak < ect && lst <= inferpeak )
    2622 {
    2623 capacity -= demands[j];
    2624 reported[j] = TRUE;
    2625
    2626 maxlst = MAX(maxlst, lst);
    2627 minect = MIN(minect, ect);
    2628 assert(maxlst < minect);
    2629
    2630 if( explanation != NULL )
    2631 explanation[j] = TRUE;
    2632 }
    2633 }
    2634
    2635 if( capacity >= 0 )
    2636 {
    2637 int* cands;
    2638 int* canddemands;
    2639 int ncands;
    2640 int c;
    2641
    2642 SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
    2643 SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
    2644 ncands = 0;
    2645
    2646 /* collect all cores of the variables which lay in the considered time window except the inference variable */
    2647 for( j = 0; j < nvars; ++j )
    2648 {
    2649 var = vars[j];
    2650 assert(var != NULL);
    2651
    2652 /* skip inference variable */
    2653 if( var == infervar || reported[j] )
    2654 continue;
    2655
    2656 duration = durations[j];
    2657 assert(duration > 0);
    2658
    2659 /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
    2660 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
    2661 assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
    2662 assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
    2663 assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
    2664
    2665 /* collect local core information */
    2666 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
    2668
    2669 SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
    2670 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
    2671 SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
    2672
    2673 /* check if the inference peak is part of the core */
    2674 if( inferpeak < ect && lst <= inferpeak )
    2675 {
    2676 cands[ncands] = j;
    2677 canddemands[ncands] = demands[j];
    2678 ncands++;
    2679
    2680 capacity -= demands[j];
    2681 }
    2682 }
    2683
    2684 /* sort candidates indices w.r.t. their demands */
    2685 SCIPsortDownIntInt(canddemands, cands, ncands);
    2686
    2687 assert(capacity < 0);
    2688 assert(ncands > 0);
    2689
    2690 /* greedily remove candidates form the list such that the needed capacity is still exceeded */
    2691 while( capacity + canddemands[ncands-1] < 0 )
    2692 {
    2693 ncands--;
    2694 capacity += canddemands[ncands];
    2695 assert(ncands > 0);
    2696 }
    2697
    2698 /* compute the size (number of time steps) of the job cores */
    2699 for( c = 0; c < ncands; ++c )
    2700 {
    2701 var = vars[cands[c]];
    2702 assert(var != NULL);
    2703
    2704 duration = durations[cands[c]];
    2705
    2706 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
    2708
    2709 maxlst = MAX(maxlst, lst);
    2710 minect = MIN(minect, ect);
    2711 assert(maxlst < minect);
    2712 }
    2713
    2714 SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
    2715 assert(inferpeak >= maxlst);
    2716 assert(inferpeak < minect);
    2717
    2718 /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
    2719 if( relaxedpeak < inferpeak )
    2720 {
    2721 inferpeak = MAX(maxlst, relaxedpeak);
    2722 }
    2723 else if( relaxedpeak > inferpeak )
    2724 {
    2725 inferpeak = MIN(minect-1, relaxedpeak);
    2726 }
    2727 assert(inferpeak >= hmin);
    2728 assert(inferpeak < hmax);
    2729 assert(inferpeak >= maxlst);
    2730 assert(inferpeak < minect);
    2731
    2732 /* post all necessary bound changes */
    2733 for( c = 0; c < ncands; ++c )
    2734 {
    2735 var = vars[cands[c]];
    2736 assert(var != NULL);
    2737
    2738 if( usebdwidening )
    2739 {
    2740 duration = durations[cands[c]];
    2741
    2742 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
    2743 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
    2744 }
    2745 else
    2746 {
    2747 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
    2748 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
    2749 }
    2750
    2751 if( explanation != NULL )
    2752 explanation[cands[c]] = TRUE;
    2753 }
    2754
    2755 SCIPfreeBufferArray(scip, &canddemands);
    2756 SCIPfreeBufferArray(scip, &cands);
    2757 }
    2758
    2759 SCIPfreeBufferArray(scip, &reported);
    2760
    2761 if( provedpeak != NULL )
    2762 *provedpeak = inferpeak;
    2763
    2764 return SCIP_OKAY;
    2765}
    2766
    2767/** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
    2768static
    2770 int begin, /**< begin of the times interval */
    2771 int end, /**< end of time interval */
    2772 int est, /**< earliest start time */
    2773 int lst, /**< latest start time */
    2774 int duration /**< duration of the job */
    2775 )
    2776{
    2777 int left;
    2778 int right;
    2779 int ect;
    2780 int lct;
    2781
    2782 ect = est + duration;
    2783 lct = lst + duration;
    2784
    2785 /* check if job runs completely within [begin,end) */
    2786 if( lct <= end && est >= begin )
    2787 return duration;
    2788
    2789 assert(lst <= end && ect >= begin);
    2790
    2791 left = ect - begin;
    2792 assert(left > 0);
    2793
    2794 right = end - lst;
    2795 assert(right > 0);
    2796
    2797 return MIN3(left, right, end - begin);
    2798}
    2799
    2800/** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
    2801 * reason
    2802 *
    2803 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
    2804 */
    2805static
    2807 SCIP* scip, /**< SCIP data structure */
    2808 int nvars, /**< number of start time variables (activities) */
    2809 SCIP_VAR** vars, /**< array of start time variables */
    2810 int* durations, /**< array of durations */
    2811 int* demands, /**< array of demands */
    2812 int capacity, /**< capacity of the cumulative condition */
    2813 int begin, /**< begin of the time window */
    2814 int end, /**< end of the time window */
    2815 SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
    2816 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
    2817 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
    2818 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
    2819 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    2820 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    2821 )
    2822{
    2823 int* locenergies;
    2824 int* overlaps;
    2825 int* idxs;
    2826
    2827 SCIP_Longint requiredenergy;
    2828 int v;
    2829
    2830 SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
    2831 SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
    2832 SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
    2833
    2834 /* energy which needs be explained */
    2835 requiredenergy = ((SCIP_Longint) end - begin) * capacity;
    2836
    2837 SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
    2838
    2839 /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
    2840 * takes
    2841 */
    2842 for( v = 0; v < nvars; ++v )
    2843 {
    2844 SCIP_VAR* var;
    2845 int glbenergy;
    2846 int duration;
    2847 int demand;
    2848 int est;
    2849 int lst;
    2850
    2851 var = vars[v];
    2852 assert(var != NULL);
    2853
    2854 locenergies[v] = 0;
    2855 overlaps[v] = 0;
    2856 idxs[v] = v;
    2857
    2858 demand = demands[v];
    2859 assert(demand > 0);
    2860
    2861 duration = durations[v];
    2862 assert(duration > 0);
    2863
    2864 /* check if the variable equals the inference variable (the one which was propagated) */
    2865 if( infervar == var )
    2866 {
    2867 int overlap;
    2868 int right;
    2869 int left;
    2870
    2871 assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
    2872
    2873 SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
    2874 SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
    2875 boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
    2876
    2877 /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
    2878 * which is necessary from the inference variable
    2879 */
    2880 if( boundtype == SCIP_BOUNDTYPE_UPPER )
    2881 {
    2882 int lct;
    2883
    2884 /* get the latest start time of the infer start time variable before the propagation took place */
    2886
    2887 /* the latest start time of the inference start time variable before the propagation needs to be smaller as
    2888 * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
    2889 * scheduled w.r.t. its latest start time
    2890 */
    2891 assert(lst < end);
    2892
    2893 /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
    2894 * interval (before the propagation)
    2895 */
    2896 right = MIN3(end - lst, end - begin, duration);
    2897
    2898 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
    2899 assert(right > 0);
    2900
    2901 lct = boundedConvertRealToInt(scip, relaxedbd) + duration;
    2902 assert(begin <= lct);
    2903 assert(bdchgidx == NULL ||
    2904 boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
    2905
    2906 /* compute the overlap of the job after the propagation but considering the relaxed bound */
    2907 left = MIN(lct - begin + 1, end - begin);
    2908 assert(left > 0);
    2909
    2910 /* compute the minimum overlap; */
    2911 overlap = MIN(left, right);
    2912 assert(overlap > 0);
    2913 assert(overlap <= end - begin);
    2914 assert(overlap <= duration);
    2915
    2916 if( usebdwidening )
    2917 {
    2918 assert(boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
    2919 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
    2920 }
    2921 else
    2922 {
    2923 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
    2924 }
    2925 }
    2926 else
    2927 {
    2928 int ect;
    2929
    2930 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
    2931
    2932 /* get the earliest completion time of the infer start time variable before the propagation took place */
    2933 ect = boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
    2934
    2935 /* the earliest start time of the inference start time variable before the propagation needs to be larger as
    2936 * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
    2937 * the job is scheduled w.r.t. its earliest start time
    2938 */
    2939 assert(ect > begin);
    2940
    2941 /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
    2942 * interval (before the propagation)
    2943 */
    2944 left = MIN3(ect - begin, end - begin, duration);
    2945
    2946 /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
    2947 assert(left > 0);
    2948
    2949 est = boundedConvertRealToInt(scip, relaxedbd);
    2950 assert(end >= est);
    2951 assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
    2952
    2953 /* compute the overlap of the job after the propagation but considering the relaxed bound */
    2954 right = MIN(end - est + 1, end - begin);
    2955 assert(right > 0);
    2956
    2957 /* compute the minimum overlap */
    2958 overlap = MIN(left, right);
    2959 assert(overlap > 0);
    2960 assert(overlap <= end - begin);
    2961 assert(overlap <= duration);
    2962
    2963 if( usebdwidening )
    2964 {
    2965 assert(boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
    2966 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
    2967 }
    2968 else
    2969 {
    2970 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
    2971 }
    2972 }
    2973
    2974 /* subtract the amount of energy which is available due to the overlap of the inference start time */
    2975 requiredenergy -= (SCIP_Longint) overlap * demand;
    2976
    2977 if( explanation != NULL )
    2978 explanation[v] = TRUE;
    2979
    2980 continue;
    2981 }
    2982
    2983 /* global time points */
    2986
    2987 glbenergy = 0;
    2988
    2989 /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
    2990 * time window
    2991 */
    2992 if( est + duration > begin && lst < end )
    2993 {
    2994 /* evaluated global contribution */
    2995 glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
    2996
    2997 /* remove the globally available energy form the required energy */
    2998 requiredenergy -= glbenergy;
    2999
    3000 if( explanation != NULL )
    3001 explanation[v] = TRUE;
    3002 }
    3003
    3004 /* local time points */
    3007
    3008 /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
    3009 * time window
    3010 */
    3011 if( est + duration > begin && lst < end )
    3012 {
    3013 overlaps[v] = computeOverlap(begin, end, est, lst, duration);
    3014
    3015 /* evaluated additionally local energy contribution */
    3016 locenergies[v] = overlaps[v] * demand - glbenergy;
    3017 assert(locenergies[v] >= 0);
    3018 }
    3019 }
    3020
    3021 /* sort the variable contributions w.r.t. additional local energy contributions */
    3022 SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
    3023
    3024 /* add local energy contributions until an overload is implied */
    3025 for( v = 0; v < nvars && requiredenergy >= 0; ++v )
    3026 {
    3027 SCIP_VAR* var;
    3028 int duration;
    3029 int overlap;
    3030 int relaxlb;
    3031 int relaxub;
    3032 int idx;
    3033
    3034 idx = idxs[v];
    3035 assert(idx >= 0 && idx < nvars);
    3036
    3037 var = vars[idx];
    3038 assert(var != NULL);
    3039 assert(var != infervar);
    3040
    3041 duration = durations[idx];
    3042 assert(duration > 0);
    3043
    3044 overlap = overlaps[v];
    3045 assert(overlap > 0);
    3046
    3047 requiredenergy -= locenergies[v];
    3048
    3049 if( requiredenergy < -1 )
    3050 {
    3051 int demand;
    3052
    3053 demand = demands[idx];
    3054 assert(demand > 0);
    3055
    3056 overlap += (int)((requiredenergy + 1) / demand);
    3057
    3058#ifndef NDEBUG
    3059 requiredenergy += locenergies[v];
    3060 requiredenergy -= (SCIP_Longint) overlap * demand;
    3061 assert(requiredenergy < 0);
    3062#endif
    3063 }
    3064 assert(overlap > 0);
    3065
    3066 relaxlb = begin - duration + overlap;
    3067 relaxub = end - overlap;
    3068
    3069 SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
    3070 SCIPvarGetName(var),
    3074 relaxlb, relaxub, demands[idx], duration);
    3075
    3076 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
    3077 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
    3078
    3079 if( explanation != NULL )
    3080 explanation[idx] = TRUE;
    3081 }
    3082
    3083 assert(requiredenergy < 0);
    3084
    3085 SCIPfreeBufferArray(scip, &idxs);
    3086 SCIPfreeBufferArray(scip, &overlaps);
    3087 SCIPfreeBufferArray(scip, &locenergies);
    3088
    3089 return SCIP_OKAY;
    3090}
    3091
    3092/** resolve propagation w.r.t. the cumulative condition */
    3093static
    3095 SCIP* scip, /**< SCIP data structure */
    3096 int nvars, /**< number of start time variables (activities) */
    3097 SCIP_VAR** vars, /**< array of start time variables */
    3098 int* durations, /**< array of durations */
    3099 int* demands, /**< array of demands */
    3100 int capacity, /**< cumulative capacity */
    3101 int hmin, /**< left bound of time axis to be considered (including hmin) */
    3102 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    3103 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
    3104 INFERINFO inferinfo, /**< the user information */
    3105 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
    3106 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
    3107 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
    3108 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    3109 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    3110 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
    3111 )
    3112{
    3113 switch( inferInfoGetProprule(inferinfo) )
    3114 {
    3116 {
    3117 int inferdemand;
    3118 int inferduration;
    3119 int inferpos;
    3120 int inferpeak;
    3121 int relaxedpeak;
    3122 int provedpeak;
    3123
    3124 /* get the position of the inferred variable in the vars array */
    3125 inferpos = inferInfoGetData1(inferinfo);
    3126 if( inferpos >= nvars || vars[inferpos] != infervar )
    3127 {
    3128 /* find inference variable in constraint */
    3129 for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
    3130 {}
    3131 }
    3132 assert(inferpos < nvars);
    3133 assert(vars[inferpos] == infervar);
    3134
    3135 inferdemand = demands[inferpos];
    3136 inferduration = durations[inferpos];
    3137
    3138 if( boundtype == SCIP_BOUNDTYPE_UPPER )
    3139 {
    3140 /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
    3141 * the inference variable
    3142 */
    3143 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
    3144
    3145 SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
    3146 SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
    3147 SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
    3148
    3149 /* get the inference peak that the time point which lead to the that propagtion */
    3150 inferpeak = inferInfoGetData2(inferinfo);
    3151 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
    3152 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
    3153 */
    3154 assert(
    3155 boundedConvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
    3156 relaxedpeak = boundedConvertRealToInt(scip, relaxedbd) + inferduration;
    3157
    3158 /* make sure that the relaxed peak is part of the effective horizon */
    3159 relaxedpeak = MIN(relaxedpeak, hmax-1);
    3160
    3161 /* make sure that relaxed peak is not larger than the infer peak
    3162 *
    3163 * This can happen in case the variable is not an active variable!
    3164 */
    3165 relaxedpeak = MAX(relaxedpeak, inferpeak);
    3166 assert(relaxedpeak >= inferpeak);
    3167 assert(relaxedpeak >= hmin);
    3168 }
    3169 else
    3170 {
    3171 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
    3172
    3173 SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
    3174 SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
    3175 SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
    3176
    3177 /* get the time interval where the job could not be scheduled */
    3178 inferpeak = inferInfoGetData2(inferinfo);
    3179 /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
    3180 * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
    3181 */
    3182 assert(boundedConvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
    3183 relaxedpeak = boundedConvertRealToInt(scip, relaxedbd) - 1;
    3184
    3185 /* make sure that the relaxed peak is part of the effective horizon */
    3186 relaxedpeak = MAX(relaxedpeak, hmin);
    3187
    3188 /* make sure that relaxed peak is not larger than the infer peak
    3189 *
    3190 * This can happen in case the variable is not an active variable!
    3191 */
    3192 relaxedpeak = MIN(relaxedpeak, inferpeak);
    3193 assert(relaxedpeak < hmax);
    3194 }
    3195
    3196 /* resolves the propagation of the core time algorithm */
    3197 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    3198 infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
    3199
    3200 if( boundtype == SCIP_BOUNDTYPE_UPPER )
    3201 {
    3202 if( usebdwidening )
    3203 {
    3204 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
    3205 }
    3206 else
    3207 {
    3208 /* old upper bound of variable itself is part of the explanation */
    3209 SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
    3210 }
    3211 }
    3212 else
    3213 {
    3214 assert(boundtype == SCIP_BOUNDTYPE_LOWER);
    3215
    3216 if( usebdwidening )
    3217 {
    3218 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
    3219 }
    3220 else
    3221 {
    3222 /* old lower bound of variable itself is part of the explanation */
    3223 SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
    3224 }
    3225 }
    3226
    3227 if( explanation != NULL )
    3228 explanation[inferpos] = TRUE;
    3229
    3230 break;
    3231 }
    3233 case PROPRULE_3_TTEF:
    3234 {
    3235 int begin;
    3236 int end;
    3237
    3238 begin = inferInfoGetData1(inferinfo);
    3239 end = inferInfoGetData2(inferinfo);
    3240 assert(begin < end);
    3241
    3242 begin = MAX(begin, hmin);
    3243 end = MIN(end, hmax);
    3244
    3245 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    3246 begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
    3247
    3248 break;
    3249 }
    3250
    3251 case PROPRULE_0_INVALID:
    3252 default:
    3253 SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
    3254 SCIPABORT();
    3255 return SCIP_INVALIDDATA; /*lint !e527*/
    3256 }
    3257
    3258 (*result) = SCIP_SUCCESS;
    3259
    3260 return SCIP_OKAY;
    3261}
    3262
    3263/**@} */
    3264
    3265
    3266/**@name Enforcement methods
    3267 *
    3268 * @{
    3269 */
    3270
    3271/** apply all fixings which are given by the alternative bounds */
    3272static
    3274 SCIP* scip, /**< SCIP data structure */
    3275 SCIP_VAR** vars, /**< array of active variables */
    3276 int nvars, /**< number of active variables */
    3277 int* alternativelbs, /**< alternative lower bounds */
    3278 int* alternativeubs, /**< alternative lower bounds */
    3279 int* downlocks, /**< number of constraints with down lock participating by the computation */
    3280 int* uplocks, /**< number of constraints with up lock participating by the computation */
    3281 SCIP_Bool* branched /**< pointer to store if a branching was applied */
    3282 )
    3283{
    3284 int v;
    3285
    3286 for( v = 0; v < nvars; ++v )
    3287 {
    3288 SCIP_VAR* var;
    3289 SCIP_Real objval;
    3290
    3291 var = vars[v];
    3292 assert(var != NULL);
    3293
    3294 objval = SCIPvarGetObj(var);
    3295
    3296 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
    3297 {
    3298 int ub;
    3299
    3301
    3302 if( alternativelbs[v] <= ub )
    3303 {
    3304 SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
    3305 (*branched) = TRUE;
    3306
    3307 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
    3308 SCIPvarGetLbLocal(var), alternativelbs[v]);
    3309
    3310 return SCIP_OKAY;
    3311 }
    3312 }
    3313
    3314 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
    3315 {
    3316 int lb;
    3317
    3319
    3320 if( alternativeubs[v] >= lb )
    3321 {
    3322 SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
    3323 (*branched) = TRUE;
    3324
    3325 SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
    3326 alternativeubs[v], SCIPvarGetUbLocal(var));
    3327
    3328 return SCIP_OKAY;
    3329 }
    3330 }
    3331 }
    3332
    3333 return SCIP_OKAY;
    3334}
    3335
    3336/** remove the capacity requirments for all job which start at the curtime */
    3337static
    3339 SCIP_CONSDATA* consdata, /**< constraint data */
    3340 int curtime, /**< current point in time */
    3341 int* starttimes, /**< array of start times */
    3342 int* startindices, /**< permutation with respect to the start times */
    3343 int* freecapacity, /**< pointer to store the resulting free capacity */
    3344 int* idx, /**< pointer to index in start time array */
    3345 int nvars /**< number of vars in array of starttimes and startindices */
    3346 )
    3347{
    3348#if defined SCIP_DEBUG && !defined NDEBUG
    3349 int oldidx;
    3350
    3351 assert(idx != NULL);
    3352 oldidx = *idx;
    3353#else
    3354 assert(idx != NULL);
    3355#endif
    3356
    3357 assert(starttimes != NULL);
    3358 assert(starttimes != NULL);
    3359 assert(freecapacity != NULL);
    3360 assert(starttimes[*idx] == curtime);
    3361 assert(consdata->demands != NULL);
    3362 assert(freecapacity != idx);
    3363
    3364 /* subtract all capacity needed up to this point */
    3365 (*freecapacity) -= consdata->demands[startindices[*idx]];
    3366
    3367 while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
    3368 {
    3369 ++(*idx);
    3370 (*freecapacity) -= consdata->demands[startindices[(*idx)]];
    3371 assert(freecapacity != idx);
    3372 }
    3373#ifdef SCIP_DEBUG
    3374 assert(oldidx <= *idx);
    3375#endif
    3376}
    3377
    3378/** add the capacity requirments for all job which end at the curtime */
    3379static
    3381 SCIP_CONSDATA* consdata, /**< constraint data */
    3382 int curtime, /**< current point in time */
    3383 int* endtimes, /**< array of end times */
    3384 int* endindices, /**< permutation with rspect to the end times */
    3385 int* freecapacity, /**< pointer to store the resulting free capacity */
    3386 int* idx, /**< pointer to index in end time array */
    3387 int nvars /**< number of vars in array of starttimes and startindices */
    3388 )
    3389{
    3390#if defined SCIP_DEBUG && !defined NDEBUG
    3391 int oldidx;
    3392 oldidx = *idx;
    3393#endif
    3394
    3395 /* free all capacity usages of jobs the are no longer running */
    3396 while( endtimes[*idx] <= curtime && *idx < nvars)
    3397 {
    3398 (*freecapacity) += consdata->demands[endindices[*idx]];
    3399 ++(*idx);
    3400 }
    3401
    3402#ifdef SCIP_DEBUG
    3403 assert(oldidx <= *idx);
    3404#endif
    3405}
    3406
    3407/** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
    3408static
    3410 SCIP* scip, /**< SCIP data structure */
    3411 SCIP_CONSDATA* consdata, /**< constraint handler data */
    3412 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    3413 int* timepoint /**< pointer to store the time point of the peak */
    3414 )
    3415{
    3416 int* starttimes; /* stores when each job is starting */
    3417 int* endtimes; /* stores when each job ends */
    3418 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    3419 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    3420
    3421 int nvars; /* number of activities for this constraint */
    3422 int freecapacity; /* remaining capacity */
    3423 int curtime; /* point in time which we are just checking */
    3424 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    3425
    3426 int hmin;
    3427 int hmax;
    3428
    3429 int j;
    3430
    3431 assert(consdata != NULL);
    3432
    3433 nvars = consdata->nvars;
    3434 assert(nvars > 0);
    3435
    3436 *timepoint = consdata->hmax;
    3437
    3438 assert(consdata->vars != NULL);
    3439
    3440 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    3441 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    3442 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    3443 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    3444
    3445 /* create event point arrays */
    3446 createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
    3447 starttimes, endtimes, startindices, endindices);
    3448
    3449 endindex = 0;
    3450 freecapacity = consdata->capacity;
    3451 hmin = consdata->hmin;
    3452 hmax = consdata->hmax;
    3453
    3454 /* check each startpoint of a job whether the capacity is kept or not */
    3455 for( j = 0; j < nvars; ++j )
    3456 {
    3457 curtime = starttimes[j];
    3458 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
    3459
    3460 if( curtime >= hmax )
    3461 break;
    3462
    3463 /* remove the capacity requirments for all job which start at the curtime */
    3464 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
    3465
    3466 /* add the capacity requirments for all job which end at the curtime */
    3467 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
    3468
    3469 assert(freecapacity <= consdata->capacity);
    3470 assert(endindex <= nvars);
    3471
    3472 /* endindex - points to the next job which will finish */
    3473 /* j - points to the last job that has been released */
    3474
    3475 /* if free capacity is smaller than zero, then add branching candidates */
    3476 if( freecapacity < 0 && curtime >= hmin )
    3477 {
    3478 *timepoint = curtime;
    3479 break;
    3480 }
    3481 } /*lint --e{850}*/
    3482
    3483 /* free all buffer arrays */
    3484 SCIPfreeBufferArray(scip, &endindices);
    3485 SCIPfreeBufferArray(scip, &startindices);
    3486 SCIPfreeBufferArray(scip, &endtimes);
    3487 SCIPfreeBufferArray(scip, &starttimes);
    3488
    3489 return SCIP_OKAY;
    3490}
    3491
    3492/** checks all cumulative constraints for infeasibility and add branching candidates to storage */
    3493static
    3495 SCIP* scip, /**< SCIP data structure */
    3496 SCIP_CONS** conss, /**< constraints to be processed */
    3497 int nconss, /**< number of constraints */
    3498 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    3499 int* nbranchcands /**< pointer to store the number of branching variables */
    3500 )
    3501{
    3502 SCIP_HASHTABLE* collectedvars;
    3503 int c;
    3504
    3505 assert(scip != NULL);
    3506 assert(conss != NULL);
    3507
    3508 /* create a hash table */
    3510 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
    3511
    3512 assert(scip != NULL);
    3513 assert(conss != NULL);
    3514
    3515 for( c = 0; c < nconss; ++c )
    3516 {
    3517 SCIP_CONS* cons;
    3518 SCIP_CONSDATA* consdata;
    3519
    3520 int curtime;
    3521 int j;
    3522
    3523 cons = conss[c];
    3524 assert(cons != NULL);
    3525
    3526 if( !SCIPconsIsActive(cons) )
    3527 continue;
    3528
    3529 consdata = SCIPconsGetData(cons);
    3530 assert(consdata != NULL);
    3531
    3532 /* get point in time when capacity is exceeded */
    3533 SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
    3534
    3535 if( curtime < consdata->hmin || curtime >= consdata->hmax )
    3536 continue;
    3537
    3538 /* report all variables that are running at that point in time */
    3539 for( j = 0; j < consdata->nvars; ++j )
    3540 {
    3541 SCIP_VAR* var;
    3542 int lb;
    3543 int ub;
    3544
    3545 var = consdata->vars[j];
    3546 assert(var != NULL);
    3547
    3548 /* check if the variable was already added */
    3549 if( SCIPhashtableExists(collectedvars, (void*)var) )
    3550 continue;
    3551
    3554
    3555 if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
    3556 {
    3557 SCIP_Real solval;
    3558 SCIP_Real score;
    3559
    3560 solval = SCIPgetSolVal(scip, sol, var);
    3561 score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
    3562
    3563 SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
    3564 SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
    3565 (*nbranchcands)++;
    3566
    3567 SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
    3568 }
    3569 }
    3570 }
    3571
    3572 SCIPhashtableFree(&collectedvars);
    3573
    3574 SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
    3575
    3576 return SCIP_OKAY;
    3577}
    3578
    3579/** enforcement of an LP, pseudo, or relaxation solution */
    3580static
    3582 SCIP* scip, /**< SCIP data structure */
    3583 SCIP_CONS** conss, /**< constraints to be processed */
    3584 int nconss, /**< number of constraints */
    3585 SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
    3586 SCIP_Bool branch, /**< should branching candidates be collected */
    3587 SCIP_RESULT* result /**< pointer to store the result */
    3588 )
    3589{
    3590 if( branch )
    3591 {
    3592 int nbranchcands;
    3593
    3594 nbranchcands = 0;
    3595 SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
    3596
    3597 if( nbranchcands > 0 )
    3598 (*result) = SCIP_INFEASIBLE;
    3599 }
    3600 else
    3601 {
    3602 SCIP_Bool violated;
    3603 int c;
    3604
    3605 violated = FALSE;
    3606
    3607 /* first check if a constraints is violated */
    3608 for( c = 0; c < nconss && !violated; ++c )
    3609 {
    3610 SCIP_CONS* cons;
    3611
    3612 cons = conss[c];
    3613 assert(cons != NULL);
    3614
    3615 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
    3616 }
    3617
    3618 if( violated )
    3619 (*result) = SCIP_INFEASIBLE;
    3620 }
    3621
    3622 return SCIP_OKAY;
    3623}
    3624
    3625/**@} */
    3626
    3627/**@name Propagation
    3628 *
    3629 * @{
    3630 */
    3631
    3632/** check if cumulative constraint is independently of all other constraints */
    3633static
    3635 SCIP_CONS* cons /**< cumulative constraint */
    3636 )
    3637{
    3638 SCIP_CONSDATA* consdata;
    3639 SCIP_VAR** vars;
    3640 SCIP_Bool* downlocks;
    3641 SCIP_Bool* uplocks;
    3642 int nvars;
    3643 int v;
    3644
    3645 consdata = SCIPconsGetData(cons);
    3646 assert(consdata != NULL);
    3647
    3648 nvars = consdata->nvars;
    3649 vars = consdata->vars;
    3650 downlocks = consdata->downlocks;
    3651 uplocks = consdata->uplocks;
    3652
    3653 /* check if the cumulative constraint has the only locks on the involved variables */
    3654 for( v = 0; v < nvars; ++v )
    3655 {
    3656 SCIP_VAR* var;
    3657
    3658 var = vars[v];
    3659 assert(var != NULL);
    3660
    3661 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
    3662 || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
    3663 return FALSE;
    3664 }
    3665
    3666 return TRUE;
    3667}
    3668
    3669/** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
    3670 * (dual reductions)
    3671 */
    3672static
    3674 SCIP* scip, /**< SCIP data structure */
    3675 SCIP_CONS* cons, /**< cumulative constraint */
    3676 SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
    3677 int* nchgbds, /**< pointer to store the number changed variable bounds */
    3678 int* nfixedvars, /**< pointer to count number of fixings */
    3679 int* ndelconss, /**< pointer to count number of deleted constraints */
    3680 SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
    3681 SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
    3682 )
    3683{
    3684 SCIP_CONSDATA* consdata;
    3685 SCIP_VAR** vars;
    3686 SCIP_Real* objvals;
    3687 SCIP_Real* lbs;
    3688 SCIP_Real* ubs;
    3689 SCIP_Real timelimit;
    3690 SCIP_Real memorylimit;
    3691 SCIP_Bool solved;
    3692 SCIP_Bool error;
    3693
    3694 int ncheckconss;
    3695 int nvars;
    3696 int v;
    3697
    3698 assert(scip != NULL);
    3699 assert(!SCIPconsIsModifiable(cons));
    3700 assert(SCIPgetNConss(scip) > 0);
    3701
    3702 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
    3703 * would/could end in an implication which can lead to cutoff of the/all optimal solution
    3704 */
    3706 return SCIP_OKAY;
    3707
    3708 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
    3709 * use the locks to decide for a dual reduction using this constraint;
    3710 */
    3711 if( !SCIPconsIsChecked(cons) )
    3712 return SCIP_OKAY;
    3713
    3714 ncheckconss = SCIPgetNCheckConss(scip);
    3715
    3716 /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
    3717 * presolved problem do nothing execpt to change the parameter settings
    3718 */
    3719 if( ncheckconss == 1 )
    3720 {
    3721 /* shrink the minimal maximum value for the conflict length */
    3722 SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
    3723
    3724 /* use only first unique implication point */
    3725 SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
    3726
    3727 /* do not use reconversion conflicts */
    3728 SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
    3729
    3730 /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
    3731 SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
    3732
    3733 /* increase the number of conflicts which induce a restart */
    3734 SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
    3735
    3736 /* weight the variable which made into a conflict */
    3737 SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
    3738
    3739 /* do not check pseudo solution (for performance reasons) */
    3740 SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
    3741
    3742 /* use value based history to detect a reasonable branching point */
    3743 SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
    3744
    3745 /* turn of LP relaxation */
    3746 SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
    3747
    3748 /* prefer the down branch in case the value based history does not suggest something */
    3749 SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
    3750
    3751 /* accept any bound change */
    3752 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
    3753
    3754 /* allow for at most 10 restart, after that the value based history should be reliable */
    3755 SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
    3756
    3757 /* set priority for depth first search to highest possible value */
    3758 SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
    3759
    3760 return SCIP_OKAY;
    3761 }
    3762
    3763 consdata = SCIPconsGetData(cons);
    3764 assert(consdata != NULL);
    3765
    3766 /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
    3767 * fail on the first place
    3768 */
    3769 if( consdata->triedsolving )
    3770 return SCIP_OKAY;
    3771
    3772 /* check if constraint is independently */
    3773 if( !isConsIndependently(cons) )
    3774 return SCIP_OKAY;
    3775
    3776 /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
    3777 * constraint is deleted; otherwise, we want to ensure that we do not try that again
    3778 */
    3779 consdata->triedsolving = TRUE;
    3780
    3781 SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
    3784
    3785 nvars = consdata->nvars;
    3786 vars = consdata->vars;
    3787
    3788 SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
    3789 SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
    3790 SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
    3791
    3792 for( v = 0; v < nvars; ++v )
    3793 {
    3794 SCIP_VAR* var;
    3795
    3796 /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
    3797 * array
    3798 */
    3799 var = vars[v];
    3800 assert(var != NULL);
    3801
    3802 lbs[v] = SCIPvarGetLbLocal(var);
    3803 ubs[v] = SCIPvarGetUbLocal(var);
    3804
    3805 objvals[v] = SCIPvarGetObj(var);
    3806 }
    3807
    3808 /* check whether there is enough time and memory left */
    3809 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
    3810 if( !SCIPisInfinity(scip, timelimit) )
    3811 timelimit -= SCIPgetSolvingTime(scip);
    3812 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
    3813
    3814 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
    3815 if( !SCIPisInfinity(scip, memorylimit) )
    3816 {
    3817 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
    3818 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
    3819 }
    3820
    3821 /* solve the cumulative condition separately */
    3822 SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
    3823 consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
    3824
    3825 if( !(*cutoff) && !(*unbounded) && !error )
    3826 {
    3827 SCIP_Bool infeasible;
    3828 SCIP_Bool tightened;
    3829 SCIP_Bool allfixed;
    3830
    3831 allfixed = TRUE;
    3832
    3833 for( v = 0; v < nvars; ++v )
    3834 {
    3835 /* check if variable is fixed */
    3836 if( lbs[v] + 0.5 > ubs[v] )
    3837 {
    3838 SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
    3839 assert(!infeasible);
    3840
    3841 if( tightened )
    3842 {
    3843 (*nfixedvars)++;
    3844 consdata->triedsolving = FALSE;
    3845 }
    3846 }
    3847 else
    3848 {
    3849 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
    3850 assert(!infeasible);
    3851
    3852 if( tightened )
    3853 {
    3854 (*nchgbds)++;
    3855 consdata->triedsolving = FALSE;
    3856 }
    3857
    3858 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
    3859 assert(!infeasible);
    3860
    3861 if( tightened )
    3862 {
    3863 (*nchgbds)++;
    3864 consdata->triedsolving = FALSE;
    3865 }
    3866
    3867 allfixed = FALSE;
    3868 }
    3869 }
    3870
    3871 /* if all variables are fixed, remove the cumulative constraint since it is redundant */
    3872 if( allfixed )
    3873 {
    3875 (*ndelconss)++;
    3876 }
    3877 }
    3878
    3879 SCIPfreeBufferArray(scip, &objvals);
    3882
    3883 return SCIP_OKAY;
    3884}
    3885
    3886/** start conflict analysis to analysis the core insertion which is infeasible */
    3887static
    3889 SCIP* scip, /**< SCIP data structure */
    3890 int nvars, /**< number of start time variables (activities) */
    3891 SCIP_VAR** vars, /**< array of start time variables */
    3892 int* durations, /**< array of durations */
    3893 int* demands, /**< array of demands */
    3894 int capacity, /**< cumulative capacity */
    3895 int hmin, /**< left bound of time axis to be considered (including hmin) */
    3896 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    3897 SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
    3898 int inferduration, /**< duration of the start time variable */
    3899 int inferdemand, /**< demand of the start time variable */
    3900 int inferpeak, /**< profile preak which causes the infeasibilty */
    3901 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    3902 SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
    3903 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    3904 )
    3905{
    3906 SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
    3907 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
    3908 SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
    3909
    3910 /* initialize conflict analysis if conflict analysis is applicable */
    3912 {
    3914
    3915 SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    3916 infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
    3917
    3918 SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
    3919
    3920 /* add both bound of the inference variable since these biuld the core which we could not inserted */
    3921 if( usebdwidening )
    3922 {
    3923 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
    3924 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
    3925 }
    3926 else
    3927 {
    3928 SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
    3929 SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
    3930 }
    3931
    3932 *initialized = TRUE;
    3933 }
    3934
    3935 return SCIP_OKAY;
    3936}
    3937
    3938/** We are using the core resource profile which contains all core except the one of the start time variable which we
    3939 * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
    3940 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
    3941 * analysis
    3942 */
    3943static
    3945 SCIP* scip, /**< SCIP data structure */
    3946 int nvars, /**< number of start time variables (activities) */
    3947 SCIP_VAR** vars, /**< array of start time variables */
    3948 int* durations, /**< array of durations */
    3949 int* demands, /**< array of demands */
    3950 int capacity, /**< cumulative capacity */
    3951 int hmin, /**< left bound of time axis to be considered (including hmin) */
    3952 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    3953 SCIP_CONS* cons, /**< constraint which is propagated */
    3954 SCIP_PROFILE* profile, /**< resource profile */
    3955 int idx, /**< position of the variable to propagate */
    3956 int* nchgbds, /**< pointer to store the number of bound changes */
    3957 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    3958 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    3959 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    3960 SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
    3961 )
    3962{
    3963 SCIP_VAR* var;
    3964 int ntimepoints;
    3965 int duration;
    3966 int demand;
    3967 int peak;
    3968 int newlb;
    3969 int est;
    3970 int lst;
    3971 int pos;
    3972
    3973 var = vars[idx];
    3974 assert(var != NULL);
    3975
    3976 duration = durations[idx];
    3977 assert(duration > 0);
    3978
    3979 demand = demands[idx];
    3980 assert(demand > 0);
    3981
    3984 ntimepoints = SCIPprofileGetNTimepoints(profile);
    3985
    3986 /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
    3987 * load which we have at the earliest start time (lower bound)
    3988 */
    3989 (void) SCIPprofileFindLeft(profile, est, &pos);
    3990
    3991 SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
    3992
    3993 /* we now trying to move the earliest start time in steps of at most "duration" length */
    3994 do
    3995 {
    3996 INFERINFO inferinfo;
    3997 SCIP_Bool tightened;
    3998 int ect;
    3999
    4000#ifndef NDEBUG
    4001 {
    4002 /* in debug mode we check that we adjust the search position correctly */
    4003 int tmppos;
    4004
    4005 (void)SCIPprofileFindLeft(profile, est, &tmppos);
    4006 assert(pos == tmppos);
    4007 }
    4008#endif
    4009 ect = est + duration;
    4010 peak = -1;
    4011
    4012 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
    4013 * want a peak which is closest to the earliest completion time
    4014 */
    4015 do
    4016 {
    4017 /* check if the profile load conflicts with the demand of the start time variable */
    4018 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
    4019 peak = pos;
    4020
    4021 pos++;
    4022 }
    4023 while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
    4024
    4025 /* if we found no peak that means current the job could be scheduled at its earliest start time without
    4026 * conflicting to the core resource profile
    4027 */
    4028 /* coverity[check_after_sink] */
    4029 if( peak == -1 )
    4030 break;
    4031
    4032 /* the peak position gives us a time point where the start time variable is in conflict with the resource
    4033 * profile. That means we have to move it to the next time point in the resource profile but at most to the
    4034 * earliest completion time (the remaining move will done in the next loop)
    4035 */
    4036 newlb = SCIPprofileGetTime(profile, peak+1);
    4037 newlb = MIN(newlb, ect);
    4038
    4039 /* if the earliest start time is greater than the lst we detected an infeasibilty */
    4040 if( newlb > lst )
    4041 {
    4042 SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
    4043
    4044 /* use conflict analysis to analysis the core insertion which was infeasible */
    4045 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    4046 var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
    4047
    4048 if( explanation != NULL )
    4049 explanation[idx] = TRUE;
    4050
    4051 *infeasible = TRUE;
    4052
    4053 break;
    4054 }
    4055
    4056 /* construct the inference information which we are using with the conflict analysis to resolve that particular
    4057 * bound change
    4058 */
    4059 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
    4060
    4061 /* perform the bound lower bound change */
    4062 if( inferInfoIsValid(inferinfo) )
    4063 {
    4064 SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
    4065 }
    4066 else
    4067 {
    4068 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
    4069 }
    4070 assert(tightened);
    4071 assert(!(*infeasible));
    4072
    4073 SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
    4074 (*nchgbds)++;
    4075
    4076 /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
    4078
    4079 /* adjust the earliest start time
    4080 *
    4081 * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
    4082 * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
    4083 * involved.
    4084 */
    4086 assert(est >= newlb);
    4087
    4088 /* adjust the search position for the resource profile for the next step */
    4089 if( est == SCIPprofileGetTime(profile, peak+1) )
    4090 pos = peak + 1;
    4091 else
    4092 pos = peak;
    4093 }
    4094 while( est < lst );
    4095
    4096 return SCIP_OKAY;
    4097}
    4098
    4099/** We are using the core resource profile which contains all core except the one of the start time variable which we
    4100 * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
    4101 * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
    4102 * analysis
    4103 */
    4104static
    4106 SCIP* scip, /**< SCIP data structure */
    4107 SCIP_VAR* var, /**< start time variable to propagate */
    4108 int duration, /**< duration of the job */
    4109 int demand, /**< demand of the job */
    4110 int capacity, /**< cumulative capacity */
    4111 SCIP_CONS* cons, /**< constraint which is propagated */
    4112 SCIP_PROFILE* profile, /**< resource profile */
    4113 int idx, /**< position of the variable to propagate */
    4114 int* nchgbds /**< pointer to store the number of bound changes */
    4115 )
    4116{
    4117 int ntimepoints;
    4118 int newub;
    4119 int peak;
    4120 int pos;
    4121 int est;
    4122 int lst;
    4123 int lct;
    4124
    4125 assert(var != NULL);
    4126 assert(duration > 0);
    4127 assert(demand > 0);
    4128
    4131
    4132 /* in case the start time variable is fixed do nothing */
    4133 if( est == lst )
    4134 return SCIP_OKAY;
    4135
    4136 ntimepoints = SCIPprofileGetNTimepoints(profile);
    4137
    4138 lct = lst + duration;
    4139
    4140 /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
    4141 * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
    4142 * position gives us the load which we have at the latest completion time minus one
    4143 */
    4144 (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
    4145
    4146 SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
    4148
    4149 if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
    4150 return SCIP_OKAY;
    4151
    4152 /* we now trying to move the latest start time in steps of at most "duration" length */
    4153 do
    4154 {
    4155 INFERINFO inferinfo;
    4156 SCIP_Bool tightened;
    4157 SCIP_Bool infeasible;
    4158
    4159 peak = -1;
    4160
    4161#ifndef NDEBUG
    4162 {
    4163 /* in debug mode we check that we adjust the search position correctly */
    4164 int tmppos;
    4165
    4166 (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
    4167 assert(pos == tmppos);
    4168 }
    4169#endif
    4170
    4171 /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
    4172 * want a peak which is closest to the latest start time
    4173 */
    4174 do
    4175 {
    4176 if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
    4177 peak = pos;
    4178
    4179 pos--;
    4180 }
    4181 while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
    4182
    4183 /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
    4184 * to the core resource profile
    4185 */
    4186 /* coverity[check_after_sink] */
    4187 if( peak == -1 )
    4188 break;
    4189
    4190 /* the peak position gives us a time point where the start time variable is in conflict with the resource
    4191 * profile. That means the job has be done until that point. Hence that gives us the latest completion
    4192 * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
    4193 * doing in the next loop)
    4194 */
    4195 newub = SCIPprofileGetTime(profile, peak);
    4196 newub = MAX(newub, lst) - duration;
    4197 assert(newub >= est);
    4198
    4199 /* construct the inference information which we are using with the conflict analysis to resolve that particular
    4200 * bound change
    4201 */
    4202 inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
    4203
    4204 /* perform the bound upper bound change */
    4205 if( inferInfoIsValid(inferinfo) )
    4206 {
    4207 SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
    4208 }
    4209 else
    4210 {
    4211 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
    4212 }
    4213 assert(tightened);
    4214 assert(!infeasible);
    4215
    4216 SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
    4217 (*nchgbds)++;
    4218
    4219 /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
    4221
    4222 /* adjust the latest start and completion time
    4223 *
    4224 * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
    4225 * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
    4226 * involved.
    4227 */
    4229 assert(lst <= newub);
    4230 lct = lst + duration;
    4231
    4232 /* adjust the search position for the resource profile for the next step */
    4233 if( SCIPprofileGetTime(profile, peak) == lct )
    4234 pos = peak - 1;
    4235 else
    4236 pos = peak;
    4237 }
    4238 while( est < lst );
    4239
    4240 return SCIP_OKAY;
    4241}
    4242
    4243/** compute for the different earliest start and latest completion time the core energy of the corresponding time
    4244 * points
    4245 */
    4246static
    4248 SCIP_PROFILE* profile, /**< core profile */
    4249 int nvars, /**< number of start time variables (activities) */
    4250 int* ests, /**< array of sorted earliest start times */
    4251 int* lcts, /**< array of sorted latest completion times */
    4252 int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
    4253 int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
    4254 )
    4255{
    4256 int ntimepoints;
    4257 int energy;
    4258 int t;
    4259 int v;
    4260
    4261 ntimepoints = SCIPprofileGetNTimepoints(profile);
    4262 t = ntimepoints - 1;
    4263 energy = 0;
    4264
    4265 /* compute core energy after the earliest start time of each job */
    4266 for( v = nvars-1; v >= 0; --v )
    4267 {
    4268 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
    4269 {
    4270 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
    4271 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
    4272 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
    4273 t--;
    4274 }
    4275 assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
    4276
    4277 /* maybe ests[j] is in-between two timepoints */
    4278 if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
    4279 {
    4280 assert(t > 0);
    4281 coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
    4282 }
    4283 else
    4284 coreEnergyAfterEst[v] = energy;
    4285 }
    4286
    4287 t = ntimepoints - 1;
    4288 energy = 0;
    4289
    4290 /* compute core energy after the latest completion time of each job */
    4291 for( v = nvars-1; v >= 0; --v )
    4292 {
    4293 while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
    4294 {
    4295 assert(SCIPprofileGetLoad(profile, t-1) >= 0);
    4296 assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
    4297 energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
    4298 t--;
    4299 }
    4300 assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
    4301
    4302 /* maybe lcts[j] is in-between two timepoints */
    4303 if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
    4304 {
    4305 assert(t > 0);
    4306 coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
    4307 }
    4308 else
    4309 coreEnergyAfterLct[v] = energy;
    4310 }
    4311}
    4312
    4313/** collect earliest start times, latest completion time, and free energy contributions */
    4314static
    4316 SCIP* scip, /**< SCIP data structure */
    4317 int nvars, /**< number of start time variables (activities) */
    4318 SCIP_VAR** vars, /**< array of start time variables */
    4319 int* durations, /**< array of durations */
    4320 int* demands, /**< array of demands */
    4321 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4322 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4323 int* permests, /**< array to store the variable positions */
    4324 int* ests, /**< array to store earliest start times */
    4325 int* permlcts, /**< array to store the variable positions */
    4326 int* lcts, /**< array to store latest completion times */
    4327 int* ects, /**< array to store earliest completion times of the flexible part of the job */
    4328 int* lsts, /**< array to store latest start times of the flexible part of the job */
    4329 int* flexenergies /**< array to store the flexible energies of each job */
    4330 )
    4331{
    4332 int v;
    4333
    4334 for( v = 0; v < nvars; ++ v)
    4335 {
    4336 int duration;
    4337 int leftadjust;
    4338 int rightadjust;
    4339 int core;
    4340 int est;
    4341 int lct;
    4342 int ect;
    4343 int lst;
    4344
    4345 duration = durations[v];
    4346 assert(duration > 0);
    4347
    4350 ect = est + duration;
    4351 lct = lst + duration;
    4352
    4353 ests[v] = est;
    4354 lcts[v] = lct;
    4355 permests[v] = v;
    4356 permlcts[v] = v;
    4357
    4358 /* compute core time window which lies within the effective horizon */
    4359 core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
    4360
    4361 /* compute the number of time steps the job could run before the effective horizon */
    4362 leftadjust = MAX(0, hmin - est);
    4363
    4364 /* compute the number of time steps the job could run after the effective horizon */
    4365 rightadjust = MAX(0, lct - hmax);
    4366
    4367 /* compute for each job the energy which is flexible; meaning not part of the core */
    4368 flexenergies[v] = duration - leftadjust - rightadjust - core;
    4369 flexenergies[v] = MAX(0, flexenergies[v]);
    4370 flexenergies[v] *= demands[v];
    4371 assert(flexenergies[v] >= 0);
    4372
    4373 /* the earliest completion time of the flexible energy */
    4374 ects[v] = MIN(ect, lst);
    4375
    4376 /* the latest start time of the flexible energy */
    4377 lsts[v] = MAX(ect, lst);
    4378 }
    4379}
    4380
    4381/** try to tighten the lower bound of the given variable */
    4382static
    4384 SCIP* scip, /**< SCIP data structure */
    4385 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4386 int nvars, /**< number of start time variables (activities) */
    4387 SCIP_VAR** vars, /**< array of start time variables */
    4388 int* durations, /**< array of durations */
    4389 int* demands, /**< array of demands */
    4390 int capacity, /**< cumulative capacity */
    4391 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4392 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4393 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
    4394 int duration, /**< duration of the job */
    4395 int demand, /**< demand of the job */
    4396 int est, /**< earliest start time of the job */
    4397 int ect, /**< earliest completion time of the flexible part of the job */
    4398 int lct, /**< latest completion time of the job */
    4399 int begin, /**< begin of the time window under investigation */
    4400 int end, /**< end of the time window under investigation */
    4401 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
    4402 int* bestlb, /**< pointer to strope the best lower bound change */
    4403 int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
    4404 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    4405 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    4406 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    4407 )
    4408{
    4409 int newlb;
    4410
    4411 assert(begin >= hmin);
    4412 assert(end <= hmax);
    4413
    4414 /* check if the time-table edge-finding should infer bounds */
    4415 if( !conshdlrdata->ttefinfer )
    4416 return SCIP_OKAY;
    4417
    4418 /* if the job can be processed completely before or after the time window, nothing can be tightened */
    4419 if( est >= end || ect <= begin )
    4420 return SCIP_OKAY;
    4421
    4422 /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
    4423 * skip since the overload check will do the job
    4424 */
    4425 if( est >= begin && ect <= end )
    4426 return SCIP_OKAY;
    4427
    4428 /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
    4429 * earliest start time
    4430 */
    4431 if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
    4432 return SCIP_OKAY;
    4433
    4434 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
    4435 * present; therefore, we need to add the core;
    4436 *
    4437 * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
    4438 * compute the earliest completion time of the (whole) job
    4439 */
    4440 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
    4441
    4442 /* compute a latest start time (upper bound) such that the job consums at most the available energy
    4443 *
    4444 * @note we can round down the compute duration w.r.t. the available energy
    4445 */
    4446 newlb = end - (int) (energy / demand);
    4447
    4448 /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
    4449 * bound (latest start time); meaning it is not possible to schedule the job
    4450 */
    4451 if( newlb > lct - duration )
    4452 {
    4453 /* initialize conflict analysis if conflict analysis is applicable */
    4455 {
    4456 SCIP_Real relaxedbd;
    4457
    4458 assert(boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
    4459
    4460 /* it is enough to overshoot the upper bound of the variable by one */
    4461 relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
    4462
    4463 /* initialize conflict analysis */
    4465
    4466 /* added to upper bound (which was overcut be new lower bound) of the variable */
    4468
    4469 /* analyze the infeasible */
    4470 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    4471 begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
    4472
    4473 (*initialized) = TRUE;
    4474 }
    4475
    4476 (*cutoff) = TRUE;
    4477 }
    4478 else if( newlb > (*bestlb) )
    4479 {
    4480 INFERINFO inferinfo;
    4481
    4482 assert(newlb > begin);
    4483
    4484 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
    4485
    4486 /* construct inference information */
    4487 (*inferinfos) = inferInfoToInt(inferinfo);
    4488 (*bestlb) = newlb;
    4489 }
    4490
    4491 return SCIP_OKAY;
    4492}
    4493
    4494/** try to tighten the upper bound of the given variable */
    4495static
    4497 SCIP* scip, /**< SCIP data structure */
    4498 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4499 int nvars, /**< number of start time variables (activities) */
    4500 SCIP_VAR** vars, /**< array of start time variables */
    4501 int* durations, /**< array of durations */
    4502 int* demands, /**< array of demands */
    4503 int capacity, /**< cumulative capacity */
    4504 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4505 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4506 SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
    4507 int duration, /**< duration of the job */
    4508 int demand, /**< demand of the job */
    4509 int est, /**< earliest start time of the job */
    4510 int lst, /**< latest start time of the flexible part of the job */
    4511 int lct, /**< latest completion time of the job */
    4512 int begin, /**< begin of the time window under investigation */
    4513 int end, /**< end of the time window under investigation */
    4514 SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
    4515 int* bestub, /**< pointer to strope the best upper bound change */
    4516 int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
    4517 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    4518 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    4519 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    4520 )
    4521{
    4522 int newub;
    4523
    4524 assert(begin >= hmin);
    4525 assert(end <= hmax);
    4526 assert(est < begin);
    4527
    4528 /* check if the time-table edge-finding should infer bounds */
    4529 if( !conshdlrdata->ttefinfer )
    4530 return SCIP_OKAY;
    4531
    4532 /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
    4533 if( lst >= end || lct <= begin )
    4534 return SCIP_OKAY;
    4535
    4536 /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
    4537 * skip since the overload check will do the job
    4538 */
    4539 if( lst >= begin && lct <= end )
    4540 return SCIP_OKAY;
    4541
    4542 /* check if the available energy in the time window is to small to handle the flexible part of the job */
    4543 if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
    4544 return SCIP_OKAY;
    4545
    4546 /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
    4547 * present; therefore, we need to add the core;
    4548 *
    4549 * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
    4550 * latest start of the (whole) job
    4551 */
    4552 energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
    4553 assert(energy >= 0);
    4554
    4555 /* compute a latest start time (upper bound) such that the job consums at most the available energy
    4556 *
    4557 * @note we can round down the compute duration w.r.t. the available energy
    4558 */
    4559 assert(demand > 0);
    4560 newub = begin - duration + (int) (energy / demand);
    4561
    4562 /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
    4563 * bound (earliest start time); meaning it is not possible to schedule the job
    4564 */
    4565 if( newub < est )
    4566 {
    4567 /* initialize conflict analysis if conflict analysis is applicable */
    4569 {
    4570 SCIP_Real relaxedbd;
    4571
    4572 assert(boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
    4573
    4574 /* it is enough to undershoot the lower bound of the variable by one */
    4575 relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
    4576
    4577 /* initialize conflict analysis */
    4579
    4580 /* added to lower bound (which was undercut be new upper bound) of the variable */
    4582
    4583 /* analyze the infeasible */
    4584 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    4585 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
    4586
    4587 (*initialized) = TRUE;
    4588 }
    4589
    4590 (*cutoff) = TRUE;
    4591 }
    4592 else if( newub < (*bestub) )
    4593 {
    4594 INFERINFO inferinfo;
    4595
    4596 assert(newub < begin);
    4597
    4598 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
    4599
    4600 /* construct inference information */
    4601 (*inferinfos) = inferInfoToInt(inferinfo);
    4602 (*bestub) = newub;
    4603 }
    4604
    4605 return SCIP_OKAY;
    4606}
    4607
    4608/** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
    4609static
    4611 SCIP* scip, /**< SCIP data structure */
    4612 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4613 int nvars, /**< number of start time variables (activities) */
    4614 SCIP_VAR** vars, /**< array of start time variables */
    4615 int* durations, /**< array of durations */
    4616 int* demands, /**< array of demands */
    4617 int capacity, /**< cumulative capacity */
    4618 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4619 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4620 int* newlbs, /**< array to buffer new lower bounds */
    4621 int* newubs, /**< array to buffer new upper bounds */
    4622 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
    4623 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
    4624 int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
    4625 int* flexenergies, /**< array of flexible energies in the same order as the variables */
    4626 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
    4627 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
    4628 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
    4629 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
    4630 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
    4631 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    4632 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    4633 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    4634 )
    4635{
    4636 int coreEnergyAfterEnd;
    4637 SCIP_Longint maxavailable;
    4638 SCIP_Longint minavailable;
    4639 SCIP_Longint totalenergy;
    4640 int nests;
    4641 int est;
    4642 int lct;
    4643 int start;
    4644 int end;
    4645 int v;
    4646
    4647 est = INT_MAX;
    4648 lct = INT_MIN;
    4649
    4650 /* compute earliest start and latest completion time of all jobs */
    4651 for( v = 0; v < nvars; ++v )
    4652 {
    4654 end = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
    4655
    4656 est = MIN(est, start);
    4657 lct = MAX(lct, end);
    4658 }
    4659
    4660 /* adjust the effective time horizon */
    4661 hmin = MAX(hmin, est);
    4662 hmax = MIN(hmax, lct);
    4663
    4664 end = hmax + 1;
    4665 coreEnergyAfterEnd = -1;
    4666
    4667 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
    4668 minavailable = maxavailable;
    4669 totalenergy = computeTotalEnergy(durations, demands, nvars);
    4670
    4671 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
    4672 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
    4673 return SCIP_OKAY;
    4674
    4675 nests = nvars;
    4676
    4677 /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
    4678 * times define the end of the time interval under investigation
    4679 */
    4680 for( v = nvars-1; v >= 0 && !(*cutoff); --v )
    4681 {
    4682 int flexenergy;
    4683 int minbegin;
    4684 int lbenergy;
    4685 int lbcand;
    4686 int i;
    4687
    4688 lct = lcts[v];
    4689
    4690 /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
    4691 * infinity capacity is available; hence we skip that
    4692 */
    4693 if( lct > hmax )
    4694 continue;
    4695
    4696 /* if the latest completion time is smaller then hmin we have to stop */
    4697 if( lct <= hmin )
    4698 {
    4699 assert(v == 0 || lcts[v-1] <= lcts[v]);
    4700 break;
    4701 }
    4702
    4703 /* if the latest completion time equals to previous end time, we can continue since this particular interval
    4704 * induced by end was just analyzed
    4705 */
    4706 if( lct == end )
    4707 continue;
    4708
    4709 assert(lct < end);
    4710
    4711 /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
    4712 * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
    4713 * free energy; if so it means that in the next iterate the free-energy cannot be negative
    4714 */
    4715 if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
    4716 {
    4717 SCIP_Longint freeenergy;
    4718
    4719 assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
    4720 assert(coreEnergyAfterEnd >= 0);
    4721
    4722 /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
    4723 freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
    4724
    4725 if( freeenergy <= minavailable )
    4726 {
    4727 SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
    4728 continue;
    4729 }
    4730 }
    4731
    4732 SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
    4733
    4734 end = lct;
    4735 coreEnergyAfterEnd = coreEnergyAfterLct[v];
    4736
    4737 flexenergy = 0;
    4738 minavailable = maxavailable;
    4739 minbegin = hmax;
    4740 lbcand = -1;
    4741 lbenergy = 0;
    4742
    4743 /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
    4744 * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
    4745 * wider
    4746 */
    4747 for( i = nests-1; i >= 0; --i )
    4748 {
    4749 SCIP_VAR* var;
    4750 SCIP_Longint freeenergy;
    4751 int duration;
    4752 int demand;
    4753 int begin;
    4754 int idx;
    4755 int lst;
    4756
    4757 idx = perm[i];
    4758 assert(idx >= 0);
    4759 assert(idx < nvars);
    4760 assert(!(*cutoff));
    4761
    4762 /* the earliest start time of the job */
    4763 est = ests[i];
    4764
    4765 /* if the job starts after the current end, we can skip it and do not need to consider it again since the
    4766 * latest completion times (which define end) are scant in non-increasing order
    4767 */
    4768 if( end <= est )
    4769 {
    4770 nests--;
    4771 continue;
    4772 }
    4773
    4774 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
    4775 * current ending time
    4776 */
    4777 if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
    4778 break;
    4779
    4780 var = vars[idx];
    4781 assert(var != NULL);
    4782
    4783 duration = durations[idx];
    4784 assert(duration > 0);
    4785
    4786 demand = demands[idx];
    4787 assert(demand > 0);
    4788
    4789 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
    4790
    4791 /* the latest start time of the free part of the job */
    4792 lst = lsts[idx];
    4793
    4794 /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
    4795 * investigation; hence the overload check will do the the job
    4796 */
    4797 assert(est <= minbegin);
    4798 if( minavailable < maxavailable && est < minbegin )
    4799 {
    4800 assert(!(*cutoff));
    4801
    4802 /* try to tighten the upper bound */
    4803 SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    4804 var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
    4805 initialized, explanation, cutoff) );
    4806
    4807 if( *cutoff )
    4808 break;
    4809 }
    4810
    4811 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
    4812 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
    4813
    4814 begin = est;
    4815 assert(boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
    4816
    4817 /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
    4818 * free energy
    4819 */
    4820 if( begin < hmin )
    4821 break;
    4822
    4823 /* compute the contribution to the flexible energy */
    4824 if( lct <= end )
    4825 {
    4826 /* if the jobs has to finish before the end, all the energy has to be scheduled */
    4827 assert(lst >= begin);
    4828 assert(flexenergies[idx] >= 0);
    4829 flexenergy += flexenergies[idx];
    4830 }
    4831 else
    4832 {
    4833 /* the job partly overlaps with the end */
    4834 int candenergy;
    4835 int energy;
    4836
    4837 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
    4838 * w.r.t. latest start time
    4839 *
    4840 * @note we need to be aware of the effective horizon
    4841 */
    4842 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
    4843 assert(end - lst < duration);
    4844 assert(energy >= 0);
    4845
    4846 /* adjust the flexible energy of the time interval */
    4847 flexenergy += energy;
    4848
    4849 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
    4850 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
    4851 assert(candenergy >= 0);
    4852
    4853 /* check if we found a better candidate */
    4854 if( candenergy > lbenergy )
    4855 {
    4856 lbenergy = candenergy;
    4857 lbcand = idx;
    4858 }
    4859 }
    4860
    4861 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
    4862 assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
    4863
    4864 /* compute the energy which is not used yet */
    4865 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
    4866
    4867 /* check overload */
    4868 if( freeenergy < 0 )
    4869 {
    4870 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
    4871
    4872 /* initialize conflict analysis if conflict analysis is applicable */
    4874 {
    4875 /* analyze infeasibilty */
    4877
    4878 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    4880 conshdlrdata->usebdwidening, explanation) );
    4881
    4882 (*initialized) = TRUE;
    4883 }
    4884
    4885 (*cutoff) = TRUE;
    4886
    4887 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
    4889
    4890 break;
    4891 }
    4892
    4893 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
    4894 if( lbenergy > 0 && freeenergy < lbenergy )
    4895 {
    4896 SCIP_Longint energy;
    4897 int newlb;
    4898 int ect;
    4899
    4900 ect = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
    4901 lst = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
    4902
    4903 /* remove the energy of our job from the ... */
    4904 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
    4905
    4906 newlb = end - (int)(energy / demands[lbcand]);
    4907
    4908 if( newlb > lst )
    4909 {
    4910 /* initialize conflict analysis if conflict analysis is applicable */
    4912 {
    4913 SCIP_Real relaxedbd;
    4914
    4915 /* analyze infeasibilty */
    4917
    4918 relaxedbd = lst + 1.0;
    4919
    4920 /* added to upper bound (which was overcut be new lower bound) of the variable */
    4921 SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
    4922
    4923 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    4924 begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
    4925 conshdlrdata->usebdwidening, explanation) );
    4926
    4927 (*initialized) = TRUE;
    4928 }
    4929
    4930 (*cutoff) = TRUE;
    4931 break;
    4932 }
    4933 else if( newlb > newlbs[lbcand] )
    4934 {
    4935 INFERINFO inferinfo;
    4936
    4937 /* construct inference information */
    4938 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
    4939
    4940 /* buffer upper bound change */
    4941 lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
    4942 newlbs[lbcand] = newlb;
    4943 }
    4944 }
    4945
    4946 /* check if the current interval has a smaller free energy */
    4947 if( minavailable > freeenergy )
    4948 {
    4949 minavailable = freeenergy;
    4950 minbegin = begin;
    4951 }
    4952 assert(minavailable >= 0);
    4953 }
    4954 }
    4955
    4956 return SCIP_OKAY;
    4957}
    4958
    4959/** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
    4960static
    4962 SCIP* scip, /**< SCIP data structure */
    4963 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    4964 int nvars, /**< number of start time variables (activities) */
    4965 SCIP_VAR** vars, /**< array of start time variables */
    4966 int* durations, /**< array of durations */
    4967 int* demands, /**< array of demands */
    4968 int capacity, /**< cumulative capacity */
    4969 int hmin, /**< left bound of time axis to be considered (including hmin) */
    4970 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    4971 int* newlbs, /**< array to buffer new lower bounds */
    4972 int* newubs, /**< array to buffer new upper bounds */
    4973 int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
    4974 int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
    4975 int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
    4976 int* flexenergies, /**< array of flexible energies in the same order as the variables */
    4977 int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
    4978 int* ests, /**< array with earliest strart times sorted in non-decreasing order */
    4979 int* lcts, /**< array with latest completion times sorted in non-decreasing order */
    4980 int* coreEnergyAfterEst, /**< core energy after the earliest start times */
    4981 int* coreEnergyAfterLct, /**< core energy after the latest completion times */
    4982 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    4983 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    4984 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    4985 )
    4986{
    4987 int coreEnergyAfterStart;
    4988 SCIP_Longint maxavailable;
    4989 SCIP_Longint minavailable;
    4990 SCIP_Longint totalenergy;
    4991 int nlcts;
    4992 int begin;
    4993 int minest;
    4994 int maxlct;
    4995 int start;
    4996 int end;
    4997 int v;
    4998
    4999 if( *cutoff )
    5000 return SCIP_OKAY;
    5001
    5002 begin = hmin - 1;
    5003
    5004 minest = INT_MAX;
    5005 maxlct = INT_MIN;
    5006
    5007 /* compute earliest start and latest completion time of all jobs */
    5008 for( v = 0; v < nvars; ++v )
    5009 {
    5011 end = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
    5012
    5013 minest = MIN(minest, start);
    5014 maxlct = MAX(maxlct, end);
    5015 }
    5016
    5017 /* adjust the effective time horizon */
    5018 hmin = MAX(hmin, minest);
    5019 hmax = MIN(hmax, maxlct);
    5020
    5021 maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
    5022 totalenergy = computeTotalEnergy(durations, demands, nvars);
    5023
    5024 /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
    5025 if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
    5026 return SCIP_OKAY;
    5027
    5028 nlcts = 0;
    5029
    5030 /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
    5031 * define the start of the time interval under investigation
    5032 */
    5033 for( v = 0; v < nvars; ++v )
    5034 {
    5035 int flexenergy;
    5036 int minend;
    5037 int ubenergy;
    5038 int ubcand;
    5039 int est;
    5040 int i;
    5041
    5042 est = ests[v];
    5043
    5044 /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
    5045 * infinity capacity is available; hence we skip that
    5046 */
    5047 if( est < hmin )
    5048 continue;
    5049
    5050 /* if the earliest start time is larger or equal then hmax we have to stop */
    5051 if( est >= hmax )
    5052 break;
    5053
    5054 /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
    5055 * induced by start was just analyzed
    5056 */
    5057 if( est == begin )
    5058 continue;
    5059
    5060 assert(est > begin);
    5061
    5062 SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
    5063
    5064 begin = est;
    5065 coreEnergyAfterStart = coreEnergyAfterEst[v];
    5066
    5067 flexenergy = 0;
    5068 minavailable = maxavailable;
    5069 minend = hmin;
    5070 ubcand = -1;
    5071 ubenergy = 0;
    5072
    5073 /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
    5074 * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
    5075 */
    5076 for( i = nlcts; i < nvars; ++i )
    5077 {
    5078 SCIP_VAR* var;
    5079 SCIP_Longint freeenergy;
    5080 int duration;
    5081 int demand;
    5082 int idx;
    5083 int lct;
    5084 int ect;
    5085
    5086 idx = perm[i];
    5087 assert(idx >= 0);
    5088 assert(idx < nvars);
    5089 assert(!(*cutoff));
    5090
    5091 /* the earliest start time of the job */
    5092 lct = lcts[i];
    5093
    5094 /* if the job has a latest completion time before the the current start, we can skip it and do not need to
    5095 * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
    5096 */
    5097 if( lct <= begin )
    5098 {
    5099 nlcts++;
    5100 continue;
    5101 }
    5102
    5103 /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
    5104 * start with current beginning time
    5105 */
    5106 if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
    5107 break;
    5108
    5109 var = vars[idx];
    5110 assert(var != NULL);
    5111
    5112 duration = durations[idx];
    5113 assert(duration > 0);
    5114
    5115 demand = demands[idx];
    5116 assert(demand > 0);
    5117
    5119
    5120 /* the earliest completion time of the flexible part of the job */
    5121 ect = ects[idx];
    5122
    5123 /* in case the latest completion time is equal to minend, the job lies completely within the time window under
    5124 * investigation; hence the overload check will do the the job
    5125 */
    5126 assert(lct >= minend);
    5127 if( minavailable < maxavailable && lct > minend )
    5128 {
    5129 assert(!(*cutoff));
    5130
    5131 /* try to tighten the upper bound */
    5132 SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    5133 var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
    5134 initialized, explanation, cutoff) );
    5135
    5136 if( *cutoff )
    5137 return SCIP_OKAY;
    5138 }
    5139
    5140 SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
    5141 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
    5142
    5143 end = lct;
    5144 assert(boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
    5145
    5146 /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
    5147 * free energy
    5148 */
    5149 if( end > hmax )
    5150 break;
    5151
    5152 /* compute the contribution to the flexible energy */
    5153 if( est >= begin )
    5154 {
    5155 /* if the jobs has to finish before the end, all the energy has to be scheduled */
    5156 assert(ect <= end);
    5157 assert(flexenergies[idx] >= 0);
    5158 flexenergy += flexenergies[idx];
    5159 }
    5160 else
    5161 {
    5162 /* the job partly overlaps with the end */
    5163 int candenergy;
    5164 int energy;
    5165
    5166 /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
    5167 * w.r.t. latest start time
    5168 *
    5169 * @note we need to be aware of the effective horizon
    5170 */
    5171 energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
    5172 assert(ect - begin < duration);
    5173 assert(energy >= 0);
    5174
    5175 /* adjust the flexible energy of the time interval */
    5176 flexenergy += energy;
    5177
    5178 /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
    5179 candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
    5180 assert(candenergy >= 0);
    5181
    5182 /* check if we found a better candidate */
    5183 if( candenergy > ubenergy )
    5184 {
    5185 ubenergy = candenergy;
    5186 ubcand = idx;
    5187 }
    5188 }
    5189
    5190 SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
    5191 assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
    5192
    5193 /* compute the energy which is not used yet */
    5194 freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
    5195
    5196 /* check overload */
    5197 if( freeenergy < 0 )
    5198 {
    5199 SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
    5200
    5201 /* initialize conflict analysis if conflict analysis is applicable */
    5203 {
    5204 /* analyze infeasibilty */
    5206
    5207 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    5209 conshdlrdata->usebdwidening, explanation) );
    5210
    5211 (*initialized) = TRUE;
    5212 }
    5213
    5214 (*cutoff) = TRUE;
    5215
    5216 /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
    5218
    5219 return SCIP_OKAY;
    5220 }
    5221
    5222 /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
    5223 if( ubenergy > 0 && freeenergy < ubenergy )
    5224 {
    5225 SCIP_Longint energy;
    5226 int newub;
    5227 int lst;
    5228
    5229 duration = durations[ubcand];
    5230 assert(duration > 0);
    5231
    5232 ect = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
    5233 lst = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
    5234
    5235 /* remove the energy of our job from the ... */
    5236 energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
    5237
    5238 newub = begin - duration + (int)(energy / demands[ubcand]);
    5239
    5240 if( newub < ect - duration )
    5241 {
    5242 /* initialize conflict analysis if conflict analysis is applicable */
    5244 {
    5245 SCIP_Real relaxedbd;
    5246 /* analyze infeasibilty */
    5248
    5249 relaxedbd = ect - duration - 1.0;
    5250
    5251 /* added to lower bound (which was undercut be new upper bound) of the variable */
    5252 SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
    5253
    5254 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    5255 begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
    5256 conshdlrdata->usebdwidening, explanation) );
    5257
    5258 (*initialized) = TRUE;
    5259 }
    5260
    5261 (*cutoff) = TRUE;
    5262 return SCIP_OKAY;
    5263 }
    5264 else if( newub < newubs[ubcand] )
    5265 {
    5266 INFERINFO inferinfo;
    5267
    5268 /* construct inference information */
    5269 inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
    5270
    5271 /* buffer upper bound change */
    5272 ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
    5273 newubs[ubcand] = newub;
    5274 }
    5275 }
    5276
    5277 /* check if the current interval has a smaller free energy */
    5278 if( minavailable > freeenergy )
    5279 {
    5280 minavailable = freeenergy;
    5281 minend = end;
    5282 }
    5283 assert(minavailable >= 0);
    5284 }
    5285 }
    5286
    5287 return SCIP_OKAY;
    5288}
    5289
    5290/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
    5291 * edge-finding
    5292 *
    5293 * @note The algorithm is based on the following two papers:
    5294 * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
    5295 * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
    5296 * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
    5297 * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
    5298 * Cumulative Resource Constraint (submitted to CPAIOR 2013)
    5299 */
    5300static
    5302 SCIP* scip, /**< SCIP data structure */
    5303 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    5304 SCIP_PROFILE* profile, /**< current core profile */
    5305 int nvars, /**< number of start time variables (activities) */
    5306 SCIP_VAR** vars, /**< array of start time variables */
    5307 int* durations, /**< array of durations */
    5308 int* demands, /**< array of demands */
    5309 int capacity, /**< cumulative capacity */
    5310 int hmin, /**< left bound of time axis to be considered (including hmin) */
    5311 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    5312 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
    5313 int* nchgbds, /**< pointer to store the number of bound changes */
    5314 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    5315 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    5316 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    5317 )
    5318{
    5319 int* coreEnergyAfterEst;
    5320 int* coreEnergyAfterLct;
    5321 int* flexenergies;
    5322 int* permests;
    5323 int* permlcts;
    5324 int* lcts;
    5325 int* ests;
    5326 int* ects;
    5327 int* lsts;
    5328
    5329 int* newlbs;
    5330 int* newubs;
    5331 int* lbinferinfos;
    5332 int* ubinferinfos;
    5333
    5334 int v;
    5335
    5336 /* check if a cutoff was already detected */
    5337 if( (*cutoff) )
    5338 return SCIP_OKAY;
    5339
    5340 /* check if at least the basic overload checking should be perfomed */
    5341 if( !conshdlrdata->ttefcheck )
    5342 return SCIP_OKAY;
    5343
    5344 SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
    5345
    5346 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
    5347 SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
    5348 SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
    5349 SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
    5350 SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
    5351 SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
    5352 SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
    5353 SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
    5354 SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
    5355
    5356 SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
    5357 SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
    5358 SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
    5359 SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
    5360
    5361 /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
    5362 for( v = 0; v < nvars; ++v )
    5363 {
    5364 newlbs[v] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
    5365 newubs[v] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
    5366 lbinferinfos[v] = 0;
    5367 ubinferinfos[v] = 0;
    5368 }
    5369
    5370 /* collect earliest start times, latest completion time, and free energy contributions */
    5371 collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
    5372
    5373 /* sort the earliest start times and latest completion in non-decreasing order */
    5374 SCIPsortIntInt(ests, permests, nvars);
    5375 SCIPsortIntInt(lcts, permlcts, nvars);
    5376
    5377 /* compute for the different earliest start and latest completion time the core energy of the corresponding time
    5378 * points
    5379 */
    5380 computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
    5381
    5382 /* propagate the upper bounds and "opportunistically" the lower bounds */
    5383 SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    5384 newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
    5385 permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
    5386
    5387 /* propagate the lower bounds and "opportunistically" the upper bounds */
    5388 SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    5389 newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
    5390 permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
    5391
    5392 /* apply the buffer bound changes */
    5393 for( v = 0; v < nvars && !(*cutoff); ++v )
    5394 {
    5395 SCIP_Bool infeasible;
    5396 SCIP_Bool tightened;
    5397
    5398 if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
    5399 {
    5400 SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
    5401 TRUE, &infeasible, &tightened) );
    5402 }
    5403 else
    5404 {
    5405 SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
    5406 }
    5407
    5408 /* since we change first the lower bound of the variable an infeasibilty should not be detected */
    5409 assert(!infeasible);
    5410
    5411 if( tightened )
    5412 {
    5413 (*nchgbds)++;
    5414
    5415 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    5417 }
    5418
    5419 if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
    5420 {
    5421 SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
    5422 TRUE, &infeasible, &tightened) );
    5423 }
    5424 else
    5425 {
    5426 SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
    5427 }
    5428
    5429 /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
    5430 * bound update can be infeasible
    5431 */
    5432 if( infeasible )
    5433 {
    5434 /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
    5435 * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
    5436 * be analyzed in the case when begin and end exceed the 15 bit limit
    5437 */
    5439 {
    5440 INFERINFO inferinfo;
    5441 SCIP_VAR* var;
    5442 int begin;
    5443 int end;
    5444
    5445 var = vars[v];
    5446 assert(var != NULL);
    5447
    5448 /* initialize conflict analysis */
    5450
    5451 /* convert int to inference information */
    5452 inferinfo = intToInferInfo(ubinferinfos[v]);
    5453
    5454 /* collect time window from inference information */
    5455 begin = inferInfoGetData1(inferinfo);
    5456 end = inferInfoGetData2(inferinfo);
    5457 assert(begin < end);
    5458
    5459 /* added to lower bound (which was undercut be new upper bound) of the variable */
    5461
    5462 /* analysis the upper bound change */
    5463 SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
    5464 begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
    5465 conshdlrdata->usebdwidening, explanation) );
    5466
    5467 (*initialized) = TRUE;
    5468 }
    5469
    5470 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    5472
    5473 (*cutoff) = TRUE;
    5474 break;
    5475 }
    5476
    5477 if( tightened )
    5478 {
    5479 (*nchgbds)++;
    5480
    5481 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    5483 }
    5484 }
    5485
    5486 SCIPfreeBufferArray(scip, &ubinferinfos);
    5487 SCIPfreeBufferArray(scip, &lbinferinfos);
    5488 SCIPfreeBufferArray(scip, &newubs);
    5489 SCIPfreeBufferArray(scip, &newlbs);
    5490
    5491 /* free buffer arrays */
    5492 SCIPfreeBufferArray(scip, &lsts);
    5493 SCIPfreeBufferArray(scip, &ects);
    5494 SCIPfreeBufferArray(scip, &ests);
    5495 SCIPfreeBufferArray(scip, &lcts);
    5496 SCIPfreeBufferArray(scip, &permests);
    5497 SCIPfreeBufferArray(scip, &permlcts);
    5498 SCIPfreeBufferArray(scip, &flexenergies);
    5499 SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
    5500 SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
    5501
    5502 return SCIP_OKAY;
    5503}
    5504
    5505/** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
    5506 * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
    5507 * time table propagator
    5508 */
    5509static
    5511 SCIP* scip, /**< SCIP data structure */
    5512 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    5513 SCIP_PROFILE* profile, /**< core profile */
    5514 int nvars, /**< number of start time variables (activities) */
    5515 SCIP_VAR** vars, /**< array of start time variables */
    5516 int* durations, /**< array of durations */
    5517 int* demands, /**< array of demands */
    5518 int capacity, /**< cumulative capacity */
    5519 int hmin, /**< left bound of time axis to be considered (including hmin) */
    5520 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    5521 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
    5522 int* nchgbds, /**< pointer to store the number of bound changes */
    5523 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    5524 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    5525 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    5526 )
    5527{
    5528 SCIP_Bool infeasible;
    5529 int v;
    5530
    5531 assert(scip != NULL);
    5532 assert(nvars > 0);
    5533 assert(cons != NULL);
    5534 assert(cutoff != NULL);
    5535
    5536 /* check if already a cutoff was detected */
    5537 if( (*cutoff) )
    5538 return SCIP_OKAY;
    5539
    5540 /* check if the time tabling should infer bounds */
    5541 if( !conshdlrdata->ttinfer )
    5542 return SCIP_OKAY;
    5543
    5544 assert(*initialized == FALSE);
    5545
    5546 SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
    5547 SCIPconsGetName(cons), hmin, hmax, capacity);
    5548
    5549 infeasible = FALSE;
    5550
    5551 /* if core profile is empty; nothing to do */
    5552 if( SCIPprofileGetNTimepoints(profile) <= 1 )
    5553 return SCIP_OKAY;
    5554
    5555 /* start checking each job whether the bounds can be improved */
    5556 for( v = 0; v < nvars; ++v )
    5557 {
    5558 SCIP_VAR* var;
    5559 int demand;
    5560 int duration;
    5561 int begin;
    5562 int end;
    5563 int est;
    5564 int lst;
    5565
    5566 var = vars[v];
    5567 assert(var != NULL);
    5568
    5569 duration = durations[v];
    5570 assert(duration > 0);
    5571
    5572 /* collect earliest and latest start time */
    5575
    5576 /* check if the start time variables is already fixed; in that case we can ignore the job */
    5577 if( est == lst )
    5578 continue;
    5579
    5580 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
    5581 if( lst + duration <= hmin || est >= hmax )
    5582 continue;
    5583
    5584 /* compute core interval w.r.t. effective time horizon */
    5585 begin = MAX(hmin, lst);
    5586 end = MIN(hmax, est + duration);
    5587
    5588 demand = demands[v];
    5589 assert(demand > 0);
    5590
    5591 /* if the job has a core, remove it first */
    5592 if( begin < end )
    5593 {
    5594 SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
    5595 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
    5596
    5597 SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
    5598 }
    5599
    5600 /* first try to update the earliest start time */
    5601 SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
    5602 profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
    5603
    5604 if( *cutoff )
    5605 break;
    5606
    5607 /* second try to update the latest start time */
    5608 SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
    5609 profile, v, nchgbds) );
    5610
    5611 if( *cutoff )
    5612 break;
    5613
    5614 /* collect the potentially updated earliest and latest start time */
    5617
    5618 /* compute core interval w.r.t. effective time horizon */
    5619 begin = MAX(hmin, lst);
    5620 end = MIN(hmax, est + duration);
    5621
    5622 /* after updating the bound we might have a new core */
    5623 if( begin < end )
    5624 {
    5625 int pos;
    5626
    5627 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
    5628 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
    5629
    5630 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
    5631
    5632 if( infeasible )
    5633 {
    5634 /* use conflict analysis to analysis the core insertion which was infeasible */
    5635 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    5636 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
    5637
    5638 if( explanation != NULL )
    5639 explanation[v] = TRUE;
    5640
    5641 (*cutoff) = TRUE;
    5642
    5643 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    5645
    5646 break;
    5647 }
    5648 }
    5649 }
    5650
    5651 return SCIP_OKAY;
    5652}
    5653
    5654
    5655/** node data structure for the binary tree used for edgefinding (with overload checking) */
    5656struct SCIP_NodeData
    5657{
    5658 SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
    5659 SCIP_Real key; /**< key which is to insert the corresponding search node */
    5660 int est; /**< earliest start time if the node data belongs to a leaf */
    5661 int lct; /**< latest completion time if the node data belongs to a leaf */
    5662 int demand; /**< demand of the job if the node data belongs to a leaf */
    5663 int duration; /**< duration of the job if the node data belongs to a leaf */
    5664 int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
    5665 int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
    5666 SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
    5667 int energytheta; /**< energy of the subset of the jobs which are part of theta set */
    5668 int energylambda;
    5669 SCIP_Longint enveloplambda;
    5670 int idx; /**< index of the start time variable in the (global) variable array */
    5671 SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
    5672};
    5673typedef struct SCIP_NodeData SCIP_NODEDATA;
    5674
    5675
    5676/** update node data structure starting from the given node along the path to the root node */
    5677static
    5679 SCIP* scip, /**< SCIP data structure */
    5680 SCIP_BTNODE* node /**< search node which inserted */
    5681 )
    5682{
    5683 SCIP_BTNODE* left;
    5684 SCIP_BTNODE* right;
    5686 SCIP_NODEDATA* leftdata;
    5687 SCIP_NODEDATA* rightdata;
    5688
    5689 SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
    5690
    5691 if( SCIPbtnodeIsLeaf(node) )
    5692 node = SCIPbtnodeGetParent(node);
    5693
    5694 while( node != NULL )
    5695 {
    5696 /* get node data */
    5698 assert(nodedata != NULL);
    5699
    5700 /* collect node data from left node */
    5701 left = SCIPbtnodeGetLeftchild(node);
    5702 assert(left != NULL);
    5703 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    5704 assert(leftdata != NULL);
    5705
    5706 /* collect node data from right node */
    5707 right = SCIPbtnodeGetRightchild(node);
    5708 assert(right != NULL);
    5709 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    5710 assert(rightdata != NULL);
    5711
    5712 /* update envelop and energy */
    5713 if( leftdata->enveloptheta >= 0 )
    5714 {
    5715 assert(rightdata->energytheta != -1);
    5716 nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
    5717 }
    5718 else
    5719 nodedata->enveloptheta = rightdata->enveloptheta;
    5720
    5721 assert(leftdata->energytheta != -1);
    5722 assert(rightdata->energytheta != -1);
    5723 nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
    5724
    5725 if( leftdata->enveloplambda >= 0 )
    5726 {
    5727 assert(rightdata->energytheta != -1);
    5728 nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
    5729 }
    5730 else
    5731 nodedata->enveloplambda = rightdata->enveloplambda;
    5732
    5733 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
    5734 nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
    5735
    5736 SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
    5737
    5738 if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
    5739 {
    5740 assert(rightdata->energytheta != -1);
    5741 assert(leftdata->energytheta != -1);
    5742 nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
    5743 }
    5744 else if( rightdata->energylambda >= 0 )
    5745 {
    5746 assert(leftdata->energytheta != -1);
    5747 nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
    5748 }
    5749 else if( leftdata->energylambda >= 0 )
    5750 {
    5751 assert(rightdata->energytheta != -1);
    5752 nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
    5753 }
    5754 else
    5755 nodedata->energylambda = -1;
    5756
    5757 /* go to parent */
    5758 node = SCIPbtnodeGetParent(node);
    5759 }
    5760
    5761 SCIPdebugMsg(scip, "updating done\n");
    5762}
    5763
    5764/** updates the key of the first parent on the trace which comes from left */
    5765static
    5767 SCIP_BTNODE* node, /**< node to start the trace */
    5768 SCIP_Real key /**< update search key */
    5769 )
    5770{
    5771 assert(node != NULL);
    5772
    5773 while( !SCIPbtnodeIsRoot(node) )
    5774 {
    5775 SCIP_BTNODE* parent;
    5776
    5777 parent = SCIPbtnodeGetParent(node);
    5778 assert(parent != NULL);
    5779
    5780 if( SCIPbtnodeIsLeftchild(node) )
    5781 {
    5783
    5785 assert(nodedata != NULL);
    5786
    5787 nodedata->key = key;
    5788 return;
    5789 }
    5790
    5791 node = parent;
    5792 }
    5793}
    5794
    5795
    5796/** deletes the given node and updates all envelops */
    5797static
    5799 SCIP* scip, /**< SCIP data structure */
    5800 SCIP_BT* tree, /**< binary tree */
    5801 SCIP_BTNODE* node /**< node to be deleted */
    5802 )
    5803{
    5804 SCIP_BTNODE* parent;
    5805 SCIP_BTNODE* grandparent;
    5806 SCIP_BTNODE* sibling;
    5807
    5808 assert(scip != NULL);
    5809 assert(tree != NULL);
    5810 assert(node != NULL);
    5811
    5812 assert(SCIPbtnodeIsLeaf(node));
    5813 assert(!SCIPbtnodeIsRoot(node));
    5814
    5815 SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
    5816
    5817 parent = SCIPbtnodeGetParent(node);
    5818 assert(parent != NULL);
    5819 if( SCIPbtnodeIsLeftchild(node) )
    5820 {
    5821 sibling = SCIPbtnodeGetRightchild(parent);
    5823 }
    5824 else
    5825 {
    5826 sibling = SCIPbtnodeGetLeftchild(parent);
    5828 }
    5829 assert(sibling != NULL);
    5830
    5831 grandparent = SCIPbtnodeGetParent(parent);
    5832
    5833 if( grandparent != NULL )
    5834 {
    5835 /* reset parent of sibling */
    5836 SCIPbtnodeSetParent(sibling, grandparent);
    5837
    5838 /* reset child of grandparent to sibling */
    5839 if( SCIPbtnodeIsLeftchild(parent) )
    5840 {
    5841 SCIPbtnodeSetLeftchild(grandparent, sibling);
    5842 }
    5843 else
    5844 {
    5846
    5847 assert(SCIPbtnodeIsRightchild(parent));
    5848 SCIPbtnodeSetRightchild(grandparent, sibling);
    5849
    5851
    5852 updateKeyOnTrace(grandparent, nodedata->key);
    5853 }
    5854
    5855 updateEnvelope(scip, grandparent);
    5856 }
    5857 else
    5858 {
    5859 SCIPbtnodeSetParent(sibling, NULL);
    5860
    5861 SCIPbtSetRoot(tree, sibling);
    5862 }
    5863
    5864 SCIPbtnodeFree(tree, &parent);
    5865
    5866 return SCIP_OKAY;
    5867}
    5868
    5869/** moves a node form the theta set into the lambda set and updates the envelops */
    5870static
    5872 SCIP* scip, /**< SCIP data structure */
    5873 SCIP_BT* tree, /**< binary tree */
    5874 SCIP_BTNODE* node /**< node to move into the lambda set */
    5875 )
    5876{
    5878
    5879 assert(scip != NULL);
    5880 assert(tree != NULL);
    5881 assert(node != NULL);
    5882
    5884 assert(nodedata != NULL);
    5885 assert(nodedata->intheta);
    5886
    5887 /* move the contributions form the theta set into the lambda set */
    5888 assert(nodedata->enveloptheta != -1);
    5889 assert(nodedata->energytheta != -1);
    5890 assert(nodedata->enveloplambda == -1);
    5891 assert(nodedata->energylambda == -1);
    5892 nodedata->enveloplambda = nodedata->enveloptheta;
    5893 nodedata->energylambda = nodedata->energytheta;
    5894
    5895 nodedata->enveloptheta = -1;
    5896 nodedata->energytheta = 0;
    5897 nodedata->intheta = FALSE;
    5898
    5899 /* update the energy and envelop values on trace */
    5900 updateEnvelope(scip, node);
    5901
    5902 return SCIP_OKAY;
    5903}
    5904
    5905/** inserts a node into the theta set and update the envelops */
    5906static
    5908 SCIP* scip, /**< SCIP data structure */
    5909 SCIP_BT* tree, /**< binary tree */
    5910 SCIP_BTNODE* node, /**< node to insert */
    5911 SCIP_NODEDATA* nodedatas, /**< array of node data */
    5912 int* nodedataidx, /**< array of indices for node data */
    5913 int* nnodedatas /**< pointer to number of node data */
    5914 )
    5915{
    5916 /* if the tree is empty the node will be the root node */
    5917 if( SCIPbtIsEmpty(tree) )
    5918 {
    5919 SCIPbtSetRoot(tree, node);
    5920 }
    5921 else
    5922 {
    5923 SCIP_NODEDATA* newnodedata;
    5924 SCIP_NODEDATA* leafdata;
    5926 SCIP_BTNODE* leaf;
    5927 SCIP_BTNODE* newnode;
    5928 SCIP_BTNODE* parent;
    5929
    5930 leaf = SCIPbtGetRoot(tree);
    5931 assert(leaf != NULL);
    5932
    5933 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
    5934 assert(leafdata != NULL);
    5935
    5937 assert(nodedata != NULL);
    5938 assert(nodedata->intheta);
    5939
    5940 /* find the position to insert the node */
    5941 while( !SCIPbtnodeIsLeaf(leaf) )
    5942 {
    5943 if( nodedata->key < leafdata->key )
    5944 leaf = SCIPbtnodeGetLeftchild(leaf);
    5945 else
    5946 leaf = SCIPbtnodeGetRightchild(leaf);
    5947
    5948 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
    5949 assert(leafdata != NULL);
    5950 }
    5951
    5952 assert(leaf != NULL);
    5953 assert(leaf != node);
    5954
    5955 /* store node data to be able to delete them latter */
    5956 newnodedata = &nodedatas[*nnodedatas];
    5957 nodedataidx[*nnodedatas] = *nnodedatas;
    5958 ++(*nnodedatas);
    5959
    5960 /* init node data */
    5961 newnodedata->var = NULL;
    5962 newnodedata->key = SCIP_INVALID;
    5963 newnodedata->est = INT_MIN;
    5964 newnodedata->lct = INT_MAX;
    5965 newnodedata->duration = 0;
    5966 newnodedata->demand = 0;
    5967 newnodedata->enveloptheta = -1;
    5968 newnodedata->energytheta = 0;
    5969 newnodedata->enveloplambda = -1;
    5970 newnodedata->energylambda = -1;
    5971 newnodedata->idx = -1;
    5972 newnodedata->intheta = TRUE;
    5973
    5974 /* create a new node */
    5975 SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
    5976 assert(newnode != NULL);
    5977
    5978 parent = SCIPbtnodeGetParent(leaf);
    5979
    5980 if( parent != NULL )
    5981 {
    5982 SCIPbtnodeSetParent(newnode, parent);
    5983
    5984 /* check if the node is the left child */
    5985 if( SCIPbtnodeGetLeftchild(parent) == leaf )
    5986 {
    5987 SCIPbtnodeSetLeftchild(parent, newnode);
    5988 }
    5989 else
    5990 {
    5991 SCIPbtnodeSetRightchild(parent, newnode);
    5992 }
    5993 }
    5994 else
    5995 SCIPbtSetRoot(tree, newnode);
    5996
    5997 if( nodedata->key < leafdata->key )
    5998 {
    5999 /* node is on the left */
    6000 SCIPbtnodeSetLeftchild(newnode, node);
    6001 SCIPbtnodeSetRightchild(newnode, leaf);
    6002 newnodedata->key = nodedata->key;
    6003 }
    6004 else
    6005 {
    6006 /* leaf is on the left */
    6007 SCIPbtnodeSetLeftchild(newnode, leaf);
    6008 SCIPbtnodeSetRightchild(newnode, node);
    6009 newnodedata->key = leafdata->key;
    6010 }
    6011
    6012 SCIPbtnodeSetParent(leaf, newnode);
    6013 SCIPbtnodeSetParent(node, newnode);
    6014 }
    6015
    6016 /* update envelop */
    6017 updateEnvelope(scip, node);
    6018
    6019 return SCIP_OKAY;
    6020}
    6021
    6022/** returns the leaf responsible for the lambda energy */
    6023static
    6025 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
    6026 )
    6027{
    6028 SCIP_BTNODE* left;
    6029 SCIP_BTNODE* right;
    6031 SCIP_NODEDATA* leftdata;
    6032 SCIP_NODEDATA* rightdata;
    6033
    6034 assert(node != NULL);
    6035
    6037 assert(nodedata != NULL);
    6038
    6039 /* check if the node is the (responsible) leaf */
    6040 if( SCIPbtnodeIsLeaf(node) )
    6041 {
    6042 assert(!nodedata->intheta);
    6043 return node;
    6044 }
    6045
    6046 left = SCIPbtnodeGetLeftchild(node);
    6047 assert(left != NULL);
    6048
    6049 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6050 assert(leftdata != NULL);
    6051
    6052 right = SCIPbtnodeGetRightchild(node);
    6053 assert(right != NULL);
    6054
    6055 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6056 assert(rightdata != NULL);
    6057
    6058 assert(nodedata->energylambda != -1);
    6059 assert(rightdata->energytheta != -1);
    6060
    6061 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
    6063
    6064 assert(leftdata->energytheta != -1);
    6065 assert(rightdata->energylambda != -1);
    6066 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
    6067
    6069}
    6070
    6071/** returns the leaf responsible for the lambda envelop */
    6072static
    6074 SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
    6075 )
    6076{
    6077 SCIP_BTNODE* left;
    6078 SCIP_BTNODE* right;
    6080 SCIP_NODEDATA* leftdata;
    6081 SCIP_NODEDATA* rightdata;
    6082
    6083 assert(node != NULL);
    6084
    6086 assert(nodedata != NULL);
    6087
    6088 /* check if the node is the (responsible) leaf */
    6089 if( SCIPbtnodeIsLeaf(node) )
    6090 {
    6091 assert(!nodedata->intheta);
    6092 return node;
    6093 }
    6094
    6095 left = SCIPbtnodeGetLeftchild(node);
    6096 assert(left != NULL);
    6097
    6098 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6099 assert(leftdata != NULL);
    6100
    6101 right = SCIPbtnodeGetRightchild(node);
    6102 assert(right != NULL);
    6103
    6104 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6105 assert(rightdata != NULL);
    6106
    6107 assert(nodedata->enveloplambda != -1);
    6108 assert(rightdata->energytheta != -1);
    6109
    6110 /* check if the left or right child is the one defining the envelop for the lambda set */
    6111 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
    6113 else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
    6114 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
    6116
    6117 assert(rightdata->enveloplambda != -1);
    6118 assert(nodedata->enveloplambda == rightdata->enveloplambda);
    6119
    6121}
    6122
    6123
    6124/** reports all elements from set theta to generate a conflicting set */
    6125static
    6127 SCIP_BTNODE* node, /**< node within a theta subtree */
    6128 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
    6129 int* nelements, /**< pointer to store the number of elements in omegaset */
    6130 int* est, /**< pointer to store the earliest start time of the omega set */
    6131 int* lct, /**< pointer to store the latest start time of the omega set */
    6132 int* energy /**< pointer to store the energy of the omega set */
    6133 )
    6134{
    6136
    6138 assert(nodedata != NULL);
    6139
    6140 if( !SCIPbtnodeIsLeaf(node) )
    6141 {
    6142 collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
    6143 collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
    6144 }
    6145 else if( nodedata->intheta )
    6146 {
    6147 assert(nodedata->var != NULL);
    6148 SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
    6149
    6150 omegaset[*nelements] = node;
    6151 (*est) = MIN(*est, nodedata->est);
    6152 (*lct) = MAX(*lct, nodedata->lct);
    6153 (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
    6154 (*nelements)++;
    6155 }
    6156}
    6157
    6158
    6159/** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
    6160static
    6162 SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
    6163 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
    6164 int* nelements, /**< pointer to store the number of elements in omegaset */
    6165 int* est, /**< pointer to store the earliest start time of the omega set */
    6166 int* lct, /**< pointer to store the latest start time of the omega set */
    6167 int* energy /**< pointer to store the energy of the omega set */
    6168 )
    6169{
    6170 assert(node != NULL);
    6171
    6172 if( SCIPbtnodeIsLeaf(node) )
    6173 {
    6174 collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
    6175 }
    6176 else
    6177 {
    6178 SCIP_BTNODE* left;
    6179 SCIP_BTNODE* right;
    6181 SCIP_NODEDATA* leftdata;
    6182 SCIP_NODEDATA* rightdata;
    6183
    6185 assert(nodedata != NULL);
    6186
    6187 left = SCIPbtnodeGetLeftchild(node);
    6188 assert(left != NULL);
    6189
    6190 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6191 assert(leftdata != NULL);
    6192
    6193 right = SCIPbtnodeGetRightchild(node);
    6194 assert(right != NULL);
    6195
    6196 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6197 assert(rightdata != NULL);
    6198
    6200 assert(nodedata != NULL);
    6201
    6202 assert(nodedata->enveloptheta != -1);
    6203 assert(rightdata->energytheta != -1);
    6204
    6205 if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
    6206 {
    6207 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
    6208 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
    6209 }
    6210 else
    6211 {
    6212 assert(rightdata->enveloptheta != -1);
    6213 assert(nodedata->enveloptheta == rightdata->enveloptheta);
    6214 traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
    6215 }
    6216 }
    6217}
    6218
    6219/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
    6220static
    6222 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
    6223 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
    6224 int* nelements, /**< pointer to store the number of elements in omega set */
    6225 int* est, /**< pointer to store the earliest start time of the omega set */
    6226 int* lct, /**< pointer to store the latest start time of the omega set */
    6227 int* energy /**< pointer to store the energy of the omega set */
    6228 )
    6229{
    6230 SCIP_BTNODE* left;
    6231 SCIP_BTNODE* right;
    6233 SCIP_NODEDATA* leftdata;
    6234 SCIP_NODEDATA* rightdata;
    6235
    6236 assert(node != NULL);
    6237
    6239 assert(nodedata != NULL);
    6240
    6241 /* check if the node is a leaf */
    6242 if( SCIPbtnodeIsLeaf(node) )
    6243 return;
    6244
    6245 left = SCIPbtnodeGetLeftchild(node);
    6246 assert(left != NULL);
    6247
    6248 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6249 assert(leftdata != NULL);
    6250
    6251 right = SCIPbtnodeGetRightchild(node);
    6252 assert(right != NULL);
    6253
    6254 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6255 assert(rightdata != NULL);
    6256
    6257 assert(nodedata->energylambda != -1);
    6258 assert(rightdata->energytheta != -1);
    6259
    6260 if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
    6261 {
    6262 traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
    6263 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
    6264 }
    6265 else
    6266 {
    6267 assert(leftdata->energytheta != -1);
    6268 assert(rightdata->energylambda != -1);
    6269 assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
    6270
    6271 collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
    6272 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
    6273 }
    6274}
    6275
    6276/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
    6277static
    6279 SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
    6280 SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
    6281 int* nelements, /**< pointer to store the number of elements in omega set */
    6282 int* est, /**< pointer to store the earliest start time of the omega set */
    6283 int* lct, /**< pointer to store the latest start time of the omega set */
    6284 int* energy /**< pointer to store the energy of the omega set */
    6285 )
    6286{
    6287 SCIP_BTNODE* left;
    6288 SCIP_BTNODE* right;
    6290 SCIP_NODEDATA* leftdata;
    6291 SCIP_NODEDATA* rightdata;
    6292
    6293 assert(node != NULL);
    6294
    6296 assert(nodedata != NULL);
    6297
    6298 /* check if the node is a leaf */
    6299 if( SCIPbtnodeIsLeaf(node) )
    6300 {
    6301 assert(!nodedata->intheta);
    6302 return;
    6303 }
    6304
    6305 left = SCIPbtnodeGetLeftchild(node);
    6306 assert(left != NULL);
    6307
    6308 leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
    6309 assert(leftdata != NULL);
    6310
    6311 right = SCIPbtnodeGetRightchild(node);
    6312 assert(right != NULL);
    6313
    6314 rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
    6315 assert(rightdata != NULL);
    6316
    6317 assert(nodedata->enveloplambda != -1);
    6318 assert(rightdata->energytheta != -1);
    6319
    6320 if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
    6321 {
    6322 traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
    6323 collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
    6324 }
    6325 else
    6326 {
    6327 if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
    6328 && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
    6329 {
    6330 traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
    6331 traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
    6332 }
    6333 else
    6334 {
    6335 assert(rightdata->enveloplambda != -1);
    6336 assert(nodedata->enveloplambda == rightdata->enveloplambda);
    6337 traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
    6338 }
    6339 }
    6340}
    6341
    6342/** compute the energy contribution by job which corresponds to the given leaf */
    6343static
    6345 SCIP_BTNODE* node /**< leaf */
    6346 )
    6347{
    6349 int duration;
    6350
    6352 assert(nodedata != NULL);
    6353 assert(nodedata->var != NULL);
    6354
    6355 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
    6356 assert(duration > 0);
    6357
    6358 SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
    6360 SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
    6361
    6362 /* return energy which is contributed by the start time variable */
    6363 return nodedata->demand * duration;
    6364}
    6365
    6366/** comparison method for two node data w.r.t. the earliest start time */
    6367static
    6369{
    6370 int est1;
    6371 int est2;
    6372
    6373 est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
    6374 est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
    6375
    6376 return (est1 - est2);
    6377}
    6378
    6379/** comparison method for two node data w.r.t. the latest completion time */
    6380static
    6382{
    6383 SCIP_NODEDATA* nodedatas;
    6384
    6385 nodedatas = (SCIP_NODEDATA*) dataptr;
    6386 return (nodedatas[ind1].lct - nodedatas[ind2].lct);
    6387}
    6388
    6389
    6390/** an overload was detected; initialized conflict analysis, add an initial reason
    6391 *
    6392 * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
    6393 */
    6394static
    6396 SCIP* scip, /**< SCIP data structure */
    6397 SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
    6398 int capacity, /**< cumulative capacity */
    6399 int nleaves, /**< number of responsible leaves */
    6400 int est, /**< earliest start time of the ...... */
    6401 int lct, /**< latest completly time of the .... */
    6402 int reportedenergy, /**< energy which already reported */
    6403 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
    6404 int shift, /**< shift applied to all jobs before adding them to the tree */
    6405 SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
    6406 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    6407 SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    6408 )
    6409{
    6410 SCIP_Longint energy;
    6411 int j;
    6412
    6413 /* do nothing if conflict analysis is not applicable */
    6415 return SCIP_OKAY;
    6416
    6417 SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
    6418
    6419 /* compute energy of initial time window */
    6420 energy = ((SCIP_Longint) lct - est) * capacity;
    6421
    6422 /* sort the start time variables which were added to search tree w.r.t. earliest start time */
    6423 SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
    6424
    6425 /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
    6426 * thereby, compute the time window of interest
    6427 */
    6428 for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
    6429 {
    6431
    6433 assert(nodedata != NULL);
    6434
    6435 reportedenergy += computeEnergyContribution(leaves[j]);
    6436
    6437 /* adjust energy if the earliest start time decrease */
    6438 if( nodedata->est < est )
    6439 {
    6440 est = nodedata->est;
    6441 energy = ((SCIP_Longint) lct - est) * capacity;
    6442 }
    6443 }
    6444 assert(reportedenergy > energy);
    6445
    6446 SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
    6447
    6448 /* initialize conflict analysis */
    6450
    6451 /* flip earliest start time and latest completion time */
    6452 if( !propest )
    6453 {
    6454 SCIPswapInts(&est, &lct);
    6455
    6456 /* shift earliest start time and latest completion time */
    6457 lct = shift - lct;
    6458 est = shift - est;
    6459 }
    6460 else
    6461 {
    6462 /* shift earliest start time and latest completion time */
    6463 lct = lct + shift;
    6464 est = est + shift;
    6465 }
    6466
    6467 nleaves = j;
    6468
    6469 /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
    6470 * overloaded
    6471 */
    6472 for( j = nleaves-1; j >= 0; --j )
    6473 {
    6475
    6477 assert(nodedata != NULL);
    6478 assert(nodedata->var != NULL);
    6479
    6480 /* check if bound widening should be used */
    6481 if( usebdwidening )
    6482 {
    6483 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
    6484 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
    6485 }
    6486 else
    6487 {
    6490 }
    6491
    6492 if( explanation != NULL )
    6493 explanation[nodedata->idx] = TRUE;
    6494 }
    6495
    6496 (*initialized) = TRUE;
    6497
    6498 return SCIP_OKAY;
    6499}
    6500
    6501/** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
    6502 * responsible interval bounds in *est_omega and *lct_omega
    6503 */
    6504static
    6506 SCIP* scip, /**< SCIP data structure */
    6507 int duration, /**< duration of the job to move */
    6508 int demand, /**< demand of the job to move */
    6509 int capacity, /**< cumulative capacity */
    6510 int est, /**< earliest start time of the omega set */
    6511 int lct, /**< latest start time of the omega set */
    6512 int energy /**< energy of the omega set */
    6513 )
    6514{
    6515 int newest;
    6516
    6517 newest = 0;
    6518
    6519 assert(scip != NULL);
    6520
    6521 if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
    6522 {
    6523 if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
    6524 {
    6525 newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
    6526 newest += est;
    6527 }
    6528 }
    6529
    6530 return newest;
    6531}
    6532
    6533/** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
    6534 *
    6535 * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
    6536 * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
    6537 */
    6538static
    6540 SCIP* scip, /**< SCIP data structure */
    6541 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    6542 SCIP_CONS* cons, /**< constraint which is propagated */
    6543 SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
    6544 SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
    6545 int capacity, /**< cumulative capacity */
    6546 int ncands, /**< number of candidates */
    6547 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
    6548 int shift, /**< shift applied to all jobs before adding them to the tree */
    6549 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    6550 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    6551 int* nchgbds, /**< pointer to store the number of bound changes */
    6552 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    6553 )
    6554{
    6555 SCIP_NODEDATA* rootdata;
    6556 int j;
    6557
    6558 assert(!SCIPbtIsEmpty(tree));
    6559
    6560 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
    6561 assert(rootdata != NULL);
    6562
    6563 /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
    6564 for( j = ncands-1; j >= 0 && !(*cutoff); --j )
    6565 {
    6567
    6568 if( SCIPbtnodeIsRoot(leaves[j]) )
    6569 break;
    6570
    6572 assert(nodedata->est != -1);
    6573
    6574 /* check if the root lambda envelop exeeds the available capacity */
    6575 while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
    6576 {
    6577 SCIP_BTNODE** omegaset;
    6578 SCIP_BTNODE* leaf;
    6579 SCIP_NODEDATA* leafdata;
    6580 int nelements;
    6581 int energy;
    6582 int newest;
    6583 int est;
    6584 int lct;
    6585
    6586 assert(!(*cutoff));
    6587
    6588 /* find responsible leaf for the lambda envelope */
    6590 assert(leaf != NULL);
    6591 assert(SCIPbtnodeIsLeaf(leaf));
    6592
    6593 leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
    6594 assert(leafdata != NULL);
    6595 assert(!leafdata->intheta);
    6596 assert(leafdata->duration > 0);
    6597 assert(leafdata->est >= 0);
    6598
    6599 /* check if the job has to be removed since its latest completion is to large */
    6600 if( leafdata->est + leafdata->duration >= nodedata->lct )
    6601 {
    6602 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
    6603
    6604 /* the root might changed therefore we need to collect the new root node data */
    6605 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
    6606 assert(rootdata != NULL);
    6607
    6608 continue;
    6609 }
    6610
    6611 /* compute omega set */
    6612 SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
    6613
    6614 nelements = 0;
    6615 est = INT_MAX;
    6616 lct = INT_MIN;
    6617 energy = 0;
    6618
    6619 /* collect the omega set from theta set */
    6620 traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
    6621 assert(nelements > 0);
    6622 assert(nelements < ncands);
    6623
    6624 newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
    6625
    6626 /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
    6627 if( newest > lct )
    6628 {
    6629 SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
    6630
    6631 /* analyze over load */
    6632 SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
    6633 conshdlrdata->usebdwidening, initialized, explanation) );
    6634 (*cutoff) = TRUE;
    6635
    6636 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
    6638 }
    6639 else if( newest > 0 )
    6640 {
    6641 SCIP_Bool infeasible;
    6642 SCIP_Bool tightened;
    6643 INFERINFO inferinfo;
    6644
    6645 if( propest )
    6646 {
    6647 /* constuct inference information; store used propagation rule and the the time window of the omega set */
    6648 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
    6649
    6650 SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
    6651 SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
    6652
    6653 if( inferInfoIsValid(inferinfo) )
    6654 {
    6655 SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
    6656 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
    6657 }
    6658 else
    6659 {
    6660 SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
    6661 TRUE, &infeasible, &tightened) );
    6662 }
    6663
    6664 /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
    6666 }
    6667 else
    6668 {
    6669 /* constuct inference information; store used propagation rule and the the time window of the omega set */
    6670 inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
    6671
    6672 SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
    6673 SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
    6674
    6675 if( inferInfoIsValid(inferinfo) )
    6676 {
    6677 SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
    6678 cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
    6679 }
    6680 else
    6681 {
    6682 SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
    6683 TRUE, &infeasible, &tightened) );
    6684 }
    6685
    6686 /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
    6688 }
    6689
    6690 /* adjust the earliest start time */
    6691 if( tightened )
    6692 {
    6693 leafdata->est = newest;
    6694 (*nchgbds)++;
    6695 }
    6696
    6697 if( infeasible )
    6698 {
    6699 /* initialize conflict analysis if conflict analysis is applicable */
    6701 {
    6702 int i;
    6703
    6704 SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
    6705
    6707
    6708 /* add lower and upper bound of variable which leads to the infeasibilty */
    6709 SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
    6710 SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
    6711
    6712 if( explanation != NULL )
    6713 explanation[leafdata->idx] = TRUE;
    6714
    6715 /* add lower and upper bound of variable which lead to the infeasibilty */
    6716 for( i = 0; i < nelements; ++i )
    6717 {
    6718 nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
    6719 assert(nodedata != NULL);
    6720
    6723
    6724 if( explanation != NULL )
    6725 explanation[nodedata->idx] = TRUE;
    6726 }
    6727
    6728 (*initialized) = TRUE;
    6729 }
    6730
    6731 (*cutoff) = TRUE;
    6732
    6733 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
    6735 }
    6736 }
    6737
    6738 /* free omegaset array */
    6739 SCIPfreeBufferArray(scip, &omegaset);
    6740
    6741 /* delete responsible leaf from lambda */
    6742 SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
    6743
    6744 /* the root might changed therefore we need to collect the new root node data */
    6745 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
    6746 assert(rootdata != NULL);
    6747 }
    6748
    6749 /* move current job j from the theta set into the lambda set */
    6750 SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
    6751 }
    6752
    6753 return SCIP_OKAY;
    6754}
    6755
    6756/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
    6757 *
    6758 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
    6759 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
    6760 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
    6761 */
    6762static
    6764 SCIP* scip, /**< SCIP data structure */
    6765 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    6766 int nvars, /**< number of start time variables (activities) */
    6767 SCIP_VAR** vars, /**< array of start time variables */
    6768 int* durations, /**< array of durations */
    6769 int* demands, /**< array of demands */
    6770 int capacity, /**< cumulative capacity */
    6771 int hmin, /**< left bound of time axis to be considered (including hmin) */
    6772 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    6773 SCIP_CONS* cons, /**< constraint which is propagated */
    6774 SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
    6775 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    6776 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    6777 int* nchgbds, /**< pointer to store the number of bound changes */
    6778 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    6779 )
    6780{
    6781 SCIP_NODEDATA* nodedatas;
    6782 SCIP_BTNODE** leaves;
    6783 SCIP_BT* tree;
    6784 int* nodedataidx;
    6785
    6786 int totalenergy;
    6787 int nnodedatas;
    6788 int ninsertcands;
    6789 int ncands;
    6790
    6791 int shift;
    6792 int idx = -1;
    6793 int j;
    6794
    6795 assert(scip != NULL);
    6796 assert(cons != NULL);
    6797 assert(initialized != NULL);
    6798 assert(cutoff != NULL);
    6799 assert(*cutoff == FALSE);
    6800
    6801 SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
    6802
    6803 SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
    6804 SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
    6805 SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
    6806
    6807 ncands = 0;
    6808 totalenergy = 0;
    6809
    6811
    6812 /* compute the shift which we apply to compute .... latest completion time of all jobs */
    6813 if( propest )
    6814 shift = 0;
    6815 else
    6816 {
    6817 shift = 0;
    6818
    6819 /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
    6820 * earliest start time propagation to handle the latest completion times
    6821 */
    6822 for( j = 0; j < nvars; ++j )
    6823 {
    6824 int lct;
    6825
    6826 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
    6827 shift = MAX(shift, lct);
    6828 }
    6829 }
    6830
    6831 /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
    6832 * horizon
    6833 */
    6834 for( j = 0; j < nvars; ++j )
    6835 {
    6837 SCIP_VAR* var;
    6838 int duration;
    6839 int leftadjust;
    6840 int rightadjust;
    6841 int energy;
    6842 int est;
    6843 int lct;
    6844
    6845 var = vars[j];
    6846 assert(var != NULL);
    6847
    6848 duration = durations[j];
    6849 assert(duration > 0);
    6850
    6851 leftadjust = 0;
    6852 rightadjust = 0;
    6853
    6855 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
    6856
    6857 /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
    6858 * effective horizon [hmin,hmax)
    6859 */
    6860 if( conshdlrdata->useadjustedjobs )
    6861 {
    6862 if( est < hmin )
    6863 {
    6864 leftadjust = (hmin - est);
    6865 est = hmin;
    6866 }
    6867 if( lct > hmax )
    6868 {
    6869 rightadjust = (lct - hmax);
    6870 lct = hmax;
    6871 }
    6872
    6873 /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
    6874 * with the effective time horizon
    6875 */
    6876 if( duration - leftadjust - rightadjust <= 0 )
    6877 continue;
    6878 }
    6879 else if( est < hmin || lct > hmax )
    6880 continue;
    6881
    6882 energy = demands[j] * (duration - leftadjust - rightadjust);
    6883 assert(energy > 0);
    6884
    6885 totalenergy += energy;
    6886
    6887 /* flip earliest start time and latest completion time */
    6888 if( !propest )
    6889 {
    6890 SCIPswapInts(&est, &lct);
    6891
    6892 /* shift earliest start time and latest completion time */
    6893 lct = shift - lct;
    6894 est = shift - est;
    6895 }
    6896 else
    6897 {
    6898 /* shift earliest start time and latest completion time */
    6899 lct = lct - shift;
    6900 est = est - shift;
    6901 }
    6902 assert(est < lct);
    6903 assert(est >= 0);
    6904 assert(lct >= 0);
    6905
    6906 /* create search node data */
    6907 nodedata = &nodedatas[ncands];
    6908 nodedataidx[ncands] = ncands;
    6909 ++ncands;
    6910
    6911 /* initialize search node data */
    6912 /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
    6913 nodedata->key = est + j / (2.0 * nvars);
    6914 nodedata->var = var;
    6915 nodedata->est = est;
    6916 nodedata->lct = lct;
    6917 nodedata->demand = demands[j];
    6918 nodedata->duration = duration;
    6919 nodedata->leftadjust = leftadjust;
    6920 nodedata->rightadjust = rightadjust;
    6921
    6922 /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
    6923 * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
    6924 * particular time interval [a,b] against the time interval [0,b].
    6925 */
    6926 nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
    6927 nodedata->energytheta = energy;
    6928 nodedata->enveloplambda = -1;
    6929 nodedata->energylambda = -1;
    6930
    6931 nodedata->idx = j;
    6932 nodedata->intheta = TRUE;
    6933 }
    6934
    6935 nnodedatas = ncands;
    6936
    6937 /* sort (non-decreasing) the jobs w.r.t. latest completion times */
    6938 SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
    6939
    6940 ninsertcands = 0;
    6941
    6942 /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
    6943 * the root envelop detects an overload
    6944 */
    6945 for( j = 0; j < ncands; ++j )
    6946 {
    6947 SCIP_BTNODE* leaf;
    6948 SCIP_NODEDATA* rootdata;
    6949
    6950 idx = nodedataidx[j];
    6951
    6952 /* check if the new job opens a time window which size is so large that it offers more energy than the total
    6953 * energy of all candidate jobs. If so we skip that one.
    6954 */
    6955 if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
    6956 {
    6957 /* set the earliest start time to minus one to mark that candidate to be not used */
    6958 nodedatas[idx].est = -1;
    6959 continue;
    6960 }
    6961
    6962 /* create search node */
    6963 SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
    6964
    6965 /* insert new node into the theta set and updete the envelops */
    6966 SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
    6967 assert(nnodedatas <= 2*nvars);
    6968
    6969 /* move the inserted candidates together */
    6970 leaves[ninsertcands] = leaf;
    6971 ninsertcands++;
    6972
    6973 assert(!SCIPbtIsEmpty(tree));
    6974 rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
    6975 assert(rootdata != NULL);
    6976
    6977 /* check if the theta set envelops exceeds the available capacity */
    6978 if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
    6979 {
    6980 SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
    6981 (*cutoff) = TRUE;
    6982
    6983 /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
    6985
    6986 break;
    6987 }
    6988 }
    6989
    6990 /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
    6991 if( *cutoff )
    6992 {
    6993 int glbenery;
    6994 int est;
    6995 int lct;
    6996
    6997 glbenery = 0;
    6998 assert( 0 <= idx );
    6999 est = nodedatas[idx].est;
    7000 lct = nodedatas[idx].lct;
    7001
    7002 /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
    7003 * which led to an overload
    7004 */
    7005 for( j = j+1; j < ncands; ++j )
    7006 {
    7008 int duration;
    7009 int glbest;
    7010 int glblct;
    7011
    7012 idx = nodedataidx[j];
    7013 nodedata = &nodedatas[idx];
    7014 assert(nodedata != NULL);
    7015
    7016 duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
    7017
    7018 /* get latest start time */
    7020 glblct = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
    7021
    7022 /* check if parts of the jobs run with the time window defined by the last inserted job */
    7023 if( glbest < est )
    7024 duration -= (est - glbest);
    7025
    7026 if( glblct > lct )
    7027 duration -= (glblct - lct);
    7028
    7029 if( duration > 0 )
    7030 {
    7031 glbenery += nodedata->demand * duration;
    7032
    7033 if( explanation != NULL )
    7034 explanation[nodedata->idx] = TRUE;
    7035 }
    7036 }
    7037
    7038 /* analyze the overload */
    7039 SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
    7040 conshdlrdata->usebdwidening, initialized, explanation) );
    7041 }
    7042 else if( ninsertcands > 1 && conshdlrdata->efinfer )
    7043 {
    7044 /* if we have more than one job insterted and edge-finding should be performed we do it */
    7045 SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
    7046 propest, shift, initialized, explanation, nchgbds, cutoff) );
    7047 }
    7048
    7049 /* free theta tree */
    7050 SCIPbtFree(&tree);
    7051
    7052 /* free buffer arrays */
    7053 SCIPfreeBufferArray(scip, &leaves);
    7054 SCIPfreeBufferArray(scip, &nodedataidx);
    7055 SCIPfreeBufferArray(scip, &nodedatas);
    7056
    7057 return SCIP_OKAY;
    7058}
    7059
    7060/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
    7061 *
    7062 * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
    7063 * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
    7064 * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
    7065 */
    7066static
    7068 SCIP* scip, /**< SCIP data structure */
    7069 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7070 int nvars, /**< number of start time variables (activities) */
    7071 SCIP_VAR** vars, /**< array of start time variables */
    7072 int* durations, /**< array of durations */
    7073 int* demands, /**< array of demands */
    7074 int capacity, /**< cumulative capacity */
    7075 int hmin, /**< left bound of time axis to be considered (including hmin) */
    7076 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    7077 SCIP_CONS* cons, /**< constraint which is propagated */
    7078 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    7079 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    7080 int* nchgbds, /**< pointer to store the number of bound changes */
    7081 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    7082 )
    7083{
    7084 /* check if a cutoff was already detected */
    7085 if( (*cutoff) )
    7086 return SCIP_OKAY;
    7087
    7088 /* check if at least the basic overload checking should be preformed */
    7089 if( !conshdlrdata->efcheck )
    7090 return SCIP_OKAY;
    7091
    7092 /* check for overload, which may result in a cutoff */
    7093 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    7094 cons, TRUE, initialized, explanation, nchgbds, cutoff) );
    7095
    7096 /* check if a cutoff was detected */
    7097 if( (*cutoff) )
    7098 return SCIP_OKAY;
    7099
    7100 /* check if bound should be infer */
    7101 if( !conshdlrdata->efinfer )
    7102 return SCIP_OKAY;
    7103
    7104 /* check for overload, which may result in a cutoff */
    7105 SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    7106 cons, FALSE, initialized, explanation, nchgbds, cutoff) );
    7107
    7108 return SCIP_OKAY;
    7109}
    7110
    7111/** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
    7112 * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
    7113 * event points
    7114 */
    7115static
    7117 SCIP* scip, /**< SCIP data structure */
    7118 int nvars, /**< number of start time variables (activities) */
    7119 SCIP_VAR** vars, /**< array of start time variables */
    7120 int* durations, /**< array of durations */
    7121 int* demands, /**< array of demands */
    7122 int capacity, /**< cumulative capacity */
    7123 int hmin, /**< left bound of time axis to be considered (including hmin) */
    7124 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    7125 SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
    7126 )
    7127{
    7128 SCIP_VAR* var;
    7129 int* starttimes; /* stores when each job is starting */
    7130 int* endtimes; /* stores when each job ends */
    7131 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    7132 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    7133
    7134 int lb;
    7135 int ub;
    7136 int freecapacity; /* remaining capacity */
    7137 int curtime; /* point in time which we are just checking */
    7138 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    7139 int njobs;
    7140 int j;
    7141
    7142 assert(scip != NULL);
    7143 assert(redundant != NULL);
    7144
    7145 (*redundant) = TRUE;
    7146
    7147 /* if no activities are associated with this cumulative then this constraint is redundant */
    7148 if( nvars == 0 )
    7149 return SCIP_OKAY;
    7150
    7151 assert(vars != NULL);
    7152
    7153 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    7154 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    7155 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    7156 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    7157
    7158 njobs = 0;
    7159
    7160 /* assign variables, start and endpoints to arrays */
    7161 for( j = 0; j < nvars; ++j )
    7162 {
    7163 assert(durations[j] > 0);
    7164 assert(demands[j] > 0);
    7165
    7166 var = vars[j];
    7167 assert(var != NULL);
    7168
    7171
    7172 /* check if jobs runs completely outside of the effective time horizon */
    7173 if( lb >= hmax || ub <= hmin - durations[j] )
    7174 continue;
    7175
    7176 starttimes[njobs] = MAX(lb, hmin);
    7177 startindices[njobs] = j;
    7178
    7179 endtimes[njobs] = MIN(ub == INT_MAX ? ub : ub + durations[j], hmax);
    7180 endindices[njobs] = j;
    7181 assert(starttimes[njobs] <= endtimes[njobs]);
    7182 njobs++;
    7183 }
    7184
    7185 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
    7186 SCIPsortIntInt(starttimes, startindices, njobs);
    7187 SCIPsortIntInt(endtimes, endindices, njobs);
    7188
    7189 endindex = 0;
    7190 freecapacity = capacity;
    7191
    7192 /* check each start point of a job whether the capacity is violated or not */
    7193 for( j = 0; j < njobs; ++j )
    7194 {
    7195 curtime = starttimes[j];
    7196
    7197 /* stop checking, if time point is above hmax */
    7198 if( curtime >= hmax )
    7199 break;
    7200
    7201 /* subtract all capacity needed up to this point */
    7202 freecapacity -= demands[startindices[j]];
    7203 while( j+1 < njobs && starttimes[j+1] == curtime )
    7204 {
    7205 ++j;
    7206 freecapacity -= demands[startindices[j]];
    7207 }
    7208
    7209 /* free all capacity usages of jobs the are no longer running */
    7210 while( endtimes[endindex] <= curtime )
    7211 {
    7212 freecapacity += demands[endindices[endindex]];
    7213 ++endindex;
    7214 }
    7215 assert(freecapacity <= capacity);
    7216
    7217 /* check freecapacity to be smaller than zero */
    7218 if( freecapacity < 0 && curtime >= hmin )
    7219 {
    7220 (*redundant) = FALSE;
    7221 break;
    7222 }
    7223 } /*lint --e{850}*/
    7224
    7225 /* free all buffer arrays */
    7226 SCIPfreeBufferArray(scip, &endindices);
    7227 SCIPfreeBufferArray(scip, &startindices);
    7228 SCIPfreeBufferArray(scip, &endtimes);
    7229 SCIPfreeBufferArray(scip, &starttimes);
    7230
    7231 return SCIP_OKAY;
    7232}
    7233
    7234/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
    7235 * completion time
    7236 */
    7237static
    7239 SCIP* scip, /**< SCIP data structure */
    7240 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7241 SCIP_PROFILE* profile, /**< resource profile */
    7242 int nvars, /**< number of variables (jobs) */
    7243 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    7244 int* durations, /**< array containing corresponding durations */
    7245 int* demands, /**< array containing corresponding demands */
    7246 int capacity, /**< cumulative capacity */
    7247 int hmin, /**< left bound of time axis to be considered (including hmin) */
    7248 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    7249 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    7250 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    7251 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    7252 )
    7253{
    7254 int v;
    7255
    7256 /* insert all cores */
    7257 for( v = 0; v < nvars; ++v )
    7258 {
    7259 SCIP_VAR* var;
    7260 SCIP_Bool infeasible;
    7261 int duration;
    7262 int demand;
    7263 int begin;
    7264 int end;
    7265 int est;
    7266 int lst;
    7267 int pos;
    7268
    7269 var = vars[v];
    7270 assert(var != NULL);
    7273
    7274 duration = durations[v];
    7275 assert(duration > 0);
    7276
    7277 demand = demands[v];
    7278 assert(demand > 0);
    7279
    7280 /* collect earliest and latest start time */
    7283
    7284 /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
    7285 if( lst + duration <= hmin || est >= hmax )
    7286 continue;
    7287
    7288 /* compute core interval w.r.t. effective time horizon */
    7289 begin = MAX(hmin, lst);
    7290 end = MIN(hmax, est + duration);
    7291
    7292 /* check if a core exists */
    7293 if( begin >= end )
    7294 continue;
    7295
    7296 SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
    7297 SCIPvarGetName(var), est, lst, duration, demand, begin, end);
    7298
    7299 /* insert the core into core resource profile (complexity O(log n)) */
    7300 SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
    7301
    7302 /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
    7303 if( infeasible )
    7304 {
    7305 assert(begin <= SCIPprofileGetTime(profile, pos));
    7306 assert(end > SCIPprofileGetTime(profile, pos));
    7307
    7308 /* use conflict analysis to analysis the core insertion which was infeasible */
    7309 SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    7310 var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
    7311
    7312 if( explanation != NULL )
    7313 explanation[v] = TRUE;
    7314
    7315 (*cutoff) = TRUE;
    7316
    7317 /* for the statistic we count the number of times a cutoff was detected due the time-time */
    7319
    7320 break;
    7321 }
    7322 }
    7323
    7324 return SCIP_OKAY;
    7325}
    7326
    7327/** propagate the cumulative condition */
    7328static
    7330 SCIP* scip, /**< SCIP data structure */
    7331 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7332 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
    7333 int nvars, /**< number of start time variables (activities) */
    7334 SCIP_VAR** vars, /**< array of start time variables */
    7335 int* durations, /**< array of durations */
    7336 int* demands, /**< array of demands */
    7337 int capacity, /**< cumulative capacity */
    7338 int hmin, /**< left bound of time axis to be considered (including hmin) */
    7339 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    7340 SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
    7341 int* nchgbds, /**< pointer to store the number of bound changes */
    7342 SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
    7343 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    7344 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    7345 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    7346 )
    7347{
    7348 SCIP_PROFILE* profile;
    7349
    7350 SCIP_RETCODE retcode = SCIP_OKAY;
    7351
    7352 assert(nchgbds != NULL);
    7353 assert(initialized != NULL);
    7354 assert(cutoff != NULL);
    7355 assert(!(*cutoff));
    7356
    7357 /**@todo avoid always sorting the variable array */
    7358
    7359 /* check if the constraint is redundant */
    7360 SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
    7361
    7362 if( *redundant )
    7363 return SCIP_OKAY;
    7364
    7365 /* create an empty resource profile for profiling the cores of the jobs */
    7366 SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
    7367
    7368 /* create core profile (compulsory parts) */
    7369 SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
    7370 initialized, explanation, cutoff), TERMINATE );
    7371
    7372 /* propagate the job cores until nothing else can be detected */
    7373 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    7374 {
    7375 SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
    7376 nchgbds, initialized, explanation, cutoff), TERMINATE );
    7377 }
    7378
    7379 /* run edge finding propagator */
    7380 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    7381 {
    7382 SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
    7383 cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
    7384 }
    7385
    7386 /* run time-table edge-finding propagator */
    7387 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    7388 {
    7389 SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
    7390 nchgbds, initialized, explanation, cutoff), TERMINATE );
    7391 }
    7392 /* free resource profile */
    7393TERMINATE:
    7394 SCIPprofileFree(&profile);
    7395
    7396 return retcode;
    7397}
    7398
    7399/** propagate the cumulative constraint */
    7400static
    7402 SCIP* scip, /**< SCIP data structure */
    7403 SCIP_CONS* cons, /**< constraint to propagate */
    7404 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    7405 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
    7406 int* nchgbds, /**< pointer to store the number of bound changes */
    7407 int* ndelconss, /**< pointer to store the number of deleted constraints */
    7408 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    7409 )
    7410{
    7411 SCIP_CONSDATA* consdata;
    7412 SCIP_Bool initialized;
    7413 SCIP_Bool redundant;
    7414 int oldnchgbds;
    7415
    7416 assert(scip != NULL);
    7417 assert(cons != NULL);
    7418
    7419 consdata = SCIPconsGetData(cons);
    7420 assert(consdata != NULL);
    7421
    7422 oldnchgbds = *nchgbds;
    7423 initialized = FALSE;
    7424 redundant = FALSE;
    7425
    7426 if( SCIPconsIsDeleted(cons) )
    7427 {
    7428 assert(SCIPinProbing(scip));
    7429 return SCIP_OKAY;
    7430 }
    7431
    7432 /* if the constraint marked to be propagated, do nothing */
    7433 if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
    7434 return SCIP_OKAY;
    7435
    7436 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
    7437 consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
    7438 consdata->hmin, consdata->hmax, cons,
    7439 nchgbds, &redundant, &initialized, NULL, cutoff) );
    7440
    7441 if( redundant )
    7442 {
    7443 SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
    7444 SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
    7445
    7446 if( !SCIPinProbing(scip) )
    7447 {
    7449 (*ndelconss)++;
    7450 }
    7451 }
    7452 else
    7453 {
    7454 if( initialized )
    7455 {
    7456 /* run conflict analysis since it was initialized */
    7457 assert(*cutoff == TRUE);
    7458 SCIPdebugMsg(scip, "start conflict analysis\n");
    7460 }
    7461
    7462 /* if successful, reset age of constraint */
    7463 if( *cutoff || *nchgbds > oldnchgbds )
    7464 {
    7466 }
    7467 else
    7468 {
    7469 /* mark the constraint to be propagated */
    7470 consdata->propagated = TRUE;
    7471 }
    7472 }
    7473
    7474 return SCIP_OKAY;
    7475}
    7476
    7477/** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
    7478 * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
    7479 * be realize as domain reduction. Otherwise we do nothing
    7480 */
    7481static
    7483 SCIP* scip, /**< SCIP data structure */
    7484 SCIP_VAR** vars, /**< problem variables */
    7485 int nvars, /**< number of problem variables */
    7486 int probingpos, /**< variable number to apply probing on */
    7487 SCIP_Real leftub, /**< upper bound of probing variable in left branch */
    7488 SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
    7489 SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
    7490 SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
    7491 SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
    7492 SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
    7493 SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
    7494 SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
    7495 SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
    7496 SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
    7497 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
    7498 SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
    7499 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    7500 )
    7501{
    7502 SCIP_VAR* var;
    7503 SCIP_Bool tightened;
    7504
    7505 assert(probingpos >= 0);
    7506 assert(probingpos < nvars);
    7507 assert(success != NULL);
    7508 assert(cutoff != NULL);
    7509
    7510 var = vars[probingpos];
    7511 assert(var != NULL);
    7512 assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
    7513 assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
    7514 assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
    7515 assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
    7516
    7517 (*success) = FALSE;
    7518
    7520 return SCIP_OKAY;
    7521
    7522 /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
    7523 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
    7524 leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
    7525
    7526 if( (*cutoff) )
    7527 {
    7528 /* note that cutoff may occur if presolving has not been executed fully */
    7529 SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
    7530
    7531 if( tightened )
    7532 {
    7533 (*success) =TRUE;
    7534 (*nfixedvars)++;
    7535 }
    7536
    7537 return SCIP_OKAY;
    7538 }
    7539
    7540 /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
    7541 * presolving has not been executed fully
    7542 */
    7543 if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
    7544 {
    7545 /* note that cutoff may occur if presolving has not been executed fully */
    7546 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
    7547
    7548 if( tightened )
    7549 {
    7550 (*success) = TRUE;
    7551 (*nfixedvars)++;
    7552 }
    7553
    7554 return SCIP_OKAY;
    7555 }
    7556
    7557 /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
    7558 SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
    7559 rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
    7560
    7561 if( (*cutoff) )
    7562 {
    7563 /* note that cutoff may occur if presolving has not been executed fully */
    7564 SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
    7565
    7566 if( tightened )
    7567 {
    7568 (*success) =TRUE;
    7569 (*nfixedvars)++;
    7570 }
    7571
    7572 return SCIP_OKAY;
    7573 }
    7574
    7575 return SCIP_OKAY;
    7576}
    7577
    7578/** is it possible, to round variable down w.r.t. objective function */
    7579static
    7581 SCIP* scip, /**< SCIP data structure */
    7582 SCIP_VAR* var, /**< problem variable */
    7583 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
    7584 )
    7585{
    7586 SCIP_Real objval;
    7587 int scalar;
    7588
    7589 assert(roundable != NULL);
    7590
    7591 *roundable = TRUE;
    7592
    7593 /* a fixed variable can be definition always be safely rounded */
    7595 return SCIP_OKAY;
    7596
    7597 /* in case the variable is not active we need to check the object coefficient of the active variable */
    7598 if( !SCIPvarIsActive(var) )
    7599 {
    7600 SCIP_VAR* actvar;
    7601 int constant;
    7602
    7603 actvar = var;
    7604
    7605 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
    7606 assert(scalar != 0);
    7607
    7608 objval = scalar * SCIPvarGetObj(actvar);
    7609 } /*lint !e438*/
    7610 else
    7611 {
    7612 scalar = 1;
    7613 objval = SCIPvarGetObj(var);
    7614 }
    7615
    7616 /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
    7617 * (the transformed problem is always a minimization problem)
    7618 *
    7619 * @note that we need to check this condition w.r.t. active variable space
    7620 */
    7621 if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
    7622 *roundable = FALSE;
    7623
    7624 return SCIP_OKAY;
    7625}
    7626
    7627/** is it possible, to round variable up w.r.t. objective function */
    7628static
    7630 SCIP* scip, /**< SCIP data structure */
    7631 SCIP_VAR* var, /**< problem variable */
    7632 SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
    7633 )
    7634{
    7635 SCIP_Real objval;
    7636 int scalar;
    7637
    7638 assert(roundable != NULL);
    7639
    7640 *roundable = TRUE;
    7641
    7642 /* a fixed variable can be definition always be safely rounded */
    7644 return SCIP_OKAY;
    7645
    7646 /* in case the variable is not active we need to check the object coefficient of the active variable */
    7647 if( !SCIPvarIsActive(var) )
    7648 {
    7649 SCIP_VAR* actvar;
    7650 int constant;
    7651
    7652 actvar = var;
    7653
    7654 SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
    7655 assert(scalar != 0);
    7656
    7657 objval = scalar * SCIPvarGetObj(actvar);
    7658 } /*lint !e438*/
    7659 else
    7660 {
    7661 scalar = 1;
    7662 objval = SCIPvarGetObj(var);
    7663 }
    7664
    7665 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
    7666 * (the transformed problem is always a minimization problem)
    7667 *
    7668 * @note that we need to check this condition w.r.t. active variable space
    7669 */
    7670 if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
    7671 *roundable = FALSE;
    7672
    7673 return SCIP_OKAY;
    7674}
    7675
    7676/** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
    7677 * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
    7678 * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
    7679 * the only one locking this variable in the corresponding direction.
    7680 */
    7681static
    7683 SCIP* scip, /**< SCIP data structure */
    7684 SCIP_CONS** conss, /**< array of cumulative constraint constraints */
    7685 int nconss, /**< number of cumulative constraints */
    7686 SCIP_Bool local, /**< use local bounds effective horizon? */
    7687 int* alternativelbs, /**< alternative lower bounds */
    7688 int* alternativeubs, /**< alternative lower bounds */
    7689 int* downlocks, /**< number of constraints with down lock participating by the computation */
    7690 int* uplocks /**< number of constraints with up lock participating by the computation */
    7691 )
    7692{
    7693 int nvars;
    7694 int c;
    7695 int v;
    7696
    7697 for( c = 0; c < nconss; ++c )
    7698 {
    7699 SCIP_CONSDATA* consdata;
    7700 SCIP_CONS* cons;
    7701 SCIP_VAR* var;
    7702 int hmin;
    7703 int hmax;
    7704
    7705 cons = conss[c];
    7706 assert(cons != NULL);
    7707
    7708 /* ignore constraints which are already deletet and those which are not check constraints */
    7709 if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
    7710 continue;
    7711
    7712 consdata = SCIPconsGetData(cons);
    7713 assert(consdata != NULL);
    7714 assert(consdata->nvars > 1);
    7715
    7716 /* compute the hmin and hmax */
    7717 if( local )
    7718 {
    7719 SCIP_PROFILE* profile;
    7720 SCIP_RETCODE retcode;
    7721
    7722 /* create empty resource profile with infinity resource capacity */
    7723 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
    7724
    7725 /* create worst case resource profile */
    7726 retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
    7727
    7728 hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
    7729 hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
    7730
    7731 /* free worst case profile */
    7732 SCIPprofileFree(&profile);
    7733
    7734 if( retcode != SCIP_OKAY )
    7735 return retcode;
    7736 }
    7737 else
    7738 {
    7739 hmin = consdata->hmin;
    7740 hmax = consdata->hmax;
    7741 }
    7742
    7743 consdata = SCIPconsGetData(cons);
    7744 assert(consdata != NULL);
    7745
    7746 nvars = consdata->nvars;
    7747
    7748 for( v = 0; v < nvars; ++v )
    7749 {
    7750 int scalar;
    7751 int constant;
    7752 int idx;
    7753
    7754 var = consdata->vars[v];
    7755 assert(var != NULL);
    7756
    7757 /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
    7759
    7760 /* ignore variable locally fixed variables */
    7761 if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
    7762 continue;
    7763
    7764 SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
    7765 idx = SCIPvarGetProbindex(var);
    7766 assert(idx >= 0);
    7767
    7768 /* first check lower bound fixing */
    7769 if( consdata->downlocks[v] )
    7770 {
    7771 int ect;
    7772 int est;
    7773
    7774 /* the variable has a down locked */
    7775 est = scalar * boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
    7776 ect = est + consdata->durations[v];
    7777
    7778 if( ect <= hmin || hmin >= hmax )
    7779 downlocks[idx]++;
    7780 else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
    7781 {
    7782 alternativelbs[idx] = (hmin + 1 - constant) / scalar;
    7783 downlocks[idx]++;
    7784 }
    7785 }
    7786
    7787 /* second check upper bound fixing */
    7788 if( consdata->uplocks[v] )
    7789 {
    7790 int duration;
    7791 int lct;
    7792 int lst;
    7793
    7794 duration = consdata->durations[v];
    7795
    7796 /* the variable has a up lock locked */
    7797 lst = scalar * boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
    7798 lct = lst + duration;
    7799
    7800 if( lst >= hmax || hmin >= hmax )
    7801 uplocks[idx]++;
    7802 else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
    7803 {
    7804 alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
    7805 uplocks[idx]++;
    7806 }
    7807 }
    7808 }
    7809 }
    7810
    7811 return SCIP_OKAY;
    7812}
    7813
    7814/** apply all fixings which are given by the alternative bounds */
    7815static
    7817 SCIP* scip, /**< SCIP data structure */
    7818 SCIP_VAR** vars, /**< array of active variables */
    7819 int nvars, /**< number of active variables */
    7820 int* alternativelbs, /**< alternative lower bounds */
    7821 int* alternativeubs, /**< alternative lower bounds */
    7822 int* downlocks, /**< number of constraints with down lock participating by the computation */
    7823 int* uplocks, /**< number of constraints with up lock participating by the computation */
    7824 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
    7825 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    7826 )
    7827{
    7828 SCIP_Real* downimpllbs;
    7829 SCIP_Real* downimplubs;
    7830 SCIP_Real* downproplbs;
    7831 SCIP_Real* downpropubs;
    7832 SCIP_Real* upimpllbs;
    7833 SCIP_Real* upimplubs;
    7834 SCIP_Real* upproplbs;
    7835 SCIP_Real* uppropubs;
    7836 int v;
    7837
    7838 /* get temporary memory for storing probing results */
    7839 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
    7840 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
    7841 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
    7842 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
    7843 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
    7844 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
    7845 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
    7846 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
    7847
    7848 for( v = 0; v < nvars; ++v )
    7849 {
    7850 SCIP_VAR* var;
    7851 SCIP_Bool infeasible;
    7852 SCIP_Bool fixed;
    7853 SCIP_Bool roundable;
    7854 int ub;
    7855 int lb;
    7856
    7857 var = vars[v];
    7858 assert(var != NULL);
    7859
    7860 /* ignore variables for which no alternative bounds have been computed */
    7861 if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
    7862 continue;
    7863
    7866
    7867 /* ignore fixed variables */
    7868 if( ub - lb <= 0 )
    7869 continue;
    7870
    7871 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
    7872 {
    7873 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
    7874
    7875 if( roundable )
    7876 {
    7877 if( alternativelbs[v] > ub )
    7878 {
    7879 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
    7880 assert(!infeasible);
    7881 assert(fixed);
    7882
    7883 (*nfixedvars)++;
    7884
    7885 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
    7886 * constraints
    7887 */
    7889 }
    7890 else
    7891 {
    7892 SCIP_Bool success;
    7893
    7894 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
    7895 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
    7896 * infeasible we can apply the dual reduction; otherwise we do nothing
    7897 */
    7898 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
    7899 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
    7900 nfixedvars, &success, cutoff) );
    7901
    7902 if( success )
    7903 {
    7905 }
    7906 }
    7907 }
    7908 }
    7909
    7912
    7913 /* ignore fixed variables */
    7914 if( ub - lb <= 0 )
    7915 continue;
    7916
    7917 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
    7918 {
    7919 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
    7920
    7921 if( roundable )
    7922 {
    7923 if( alternativeubs[v] < lb )
    7924 {
    7925 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
    7926 assert(!infeasible);
    7927 assert(fixed);
    7928
    7929 (*nfixedvars)++;
    7930
    7931 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
    7932 * constraints
    7933 */
    7935 }
    7936 else
    7937 {
    7938 SCIP_Bool success;
    7939
    7940 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
    7941 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
    7942 * infeasible we can apply the dual reduction; otherwise we do nothing
    7943 */
    7944 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
    7945 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
    7946 nfixedvars, &success, cutoff) );
    7947
    7948 if( success )
    7949 {
    7951 }
    7952 }
    7953 }
    7954 }
    7955 }
    7956
    7957 /* free temporary memory */
    7958 SCIPfreeBufferArray(scip, &uppropubs);
    7959 SCIPfreeBufferArray(scip, &upproplbs);
    7960 SCIPfreeBufferArray(scip, &upimplubs);
    7961 SCIPfreeBufferArray(scip, &upimpllbs);
    7962 SCIPfreeBufferArray(scip, &downpropubs);
    7963 SCIPfreeBufferArray(scip, &downproplbs);
    7964 SCIPfreeBufferArray(scip, &downimplubs);
    7965 SCIPfreeBufferArray(scip, &downimpllbs);
    7966
    7967 return SCIP_OKAY;
    7968}
    7969
    7970/** propagate all constraints together */
    7971static
    7973 SCIP* scip, /**< SCIP data structure */
    7974 SCIP_CONS** conss, /**< all cumulative constraint */
    7975 int nconss, /**< number of cumulative constraints */
    7976 SCIP_Bool local, /**< use local bounds effective horizon? */
    7977 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
    7978 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
    7979 SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
    7980 )
    7981{ /*lint --e{715}*/
    7982 SCIP_VAR** vars;
    7983 int* downlocks;
    7984 int* uplocks;
    7985 int* alternativelbs;
    7986 int* alternativeubs;
    7987 int oldnfixedvars;
    7988 int nvars;
    7989 int v;
    7990
    7992 return SCIP_OKAY;
    7993
    7994 nvars = SCIPgetNVars(scip);
    7995 oldnfixedvars = *nfixedvars;
    7996
    7997 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
    7998 SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
    7999 SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
    8000 SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
    8001 SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
    8002
    8003 /* initialize arrays */
    8004 for( v = 0; v < nvars; ++v )
    8005 {
    8006 downlocks[v] = 0;
    8007 uplocks[v] = 0;
    8008 alternativelbs[v] = INT_MAX;
    8009 alternativeubs[v] = INT_MIN;
    8010 }
    8011
    8012 /* compute alternative bounds */
    8013 SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
    8014
    8015 /* apply fixing which result of the alternative bounds directly */
    8016 SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
    8017 nfixedvars, cutoff) );
    8018
    8019 if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
    8020 {
    8021 SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
    8022 }
    8023
    8024 /* free all buffers */
    8025 SCIPfreeBufferArray(scip, &alternativeubs);
    8026 SCIPfreeBufferArray(scip, &alternativelbs);
    8027 SCIPfreeBufferArray(scip, &uplocks);
    8028 SCIPfreeBufferArray(scip, &downlocks);
    8029 SCIPfreeBufferArray(scip, &vars);
    8030
    8031 return SCIP_OKAY;
    8032}
    8033
    8034/**@} */
    8035
    8036/**@name Linear relaxations
    8037 *
    8038 * @{
    8039 */
    8040
    8041/** creates covering cuts for jobs violating resource constraints */
    8042static
    8044 SCIP* scip, /**< SCIP data structure */
    8045 SCIP_CONS* cons, /**< constraint to be checked */
    8046 int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
    8047 int time /**< at this point in time covering constraints are valid */
    8048 )
    8049{
    8050 SCIP_CONSDATA* consdata;
    8051 SCIP_ROW* row;
    8052 int* flexibleids;
    8053 int* demands;
    8054
    8055 char rowname[SCIP_MAXSTRLEN];
    8056
    8057 int remainingcap;
    8058 int smallcoversize; /* size of a small cover */
    8059 int bigcoversize; /* size of a big cover */
    8060 int nvars;
    8061
    8062 int nflexible;
    8063 int sumdemand; /* demand of all jobs up to a certain index */
    8064 int j;
    8065
    8066 assert(cons != NULL);
    8067
    8068 /* get constraint data structure */
    8069 consdata = SCIPconsGetData(cons);
    8070 assert(consdata != NULL );
    8071
    8072 nvars = consdata->nvars;
    8073
    8074 /* sort jobs according to demands */
    8075 SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
    8076 SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
    8077
    8078 nflexible = 0;
    8079 remainingcap = consdata->capacity;
    8080
    8081 /* get all jobs intersecting point 'time' with their bounds */
    8082 for( j = 0; j < nvars; ++j )
    8083 {
    8084 int ub;
    8085
    8086 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
    8087
    8088 /* only add jobs to array if they intersect with point 'time' */
    8089 if( startvalues[j] <= time && ub + consdata->durations[j] > time )
    8090 {
    8091 /* if job is fixed, capacity has to be decreased */
    8092 if( startvalues[j] == ub )
    8093 {
    8094 remainingcap -= consdata->demands[j];
    8095 }
    8096 else
    8097 {
    8098 demands[nflexible] = consdata->demands[j];
    8099 flexibleids[nflexible] = j;
    8100 ++nflexible;
    8101 }
    8102 }
    8103 }
    8104 assert(remainingcap >= 0);
    8105
    8106 /* sort demands and job ids */
    8107 SCIPsortIntInt(demands, flexibleids, nflexible);
    8108
    8109 /*
    8110 * version 1:
    8111 * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
    8112 * erzeuge cover constraint
    8113 *
    8114 */
    8115
    8116 /* find maximum number of jobs that can run in parallel (-->coversize = j) */
    8117 sumdemand = 0;
    8118 j = 0;
    8119
    8120 while( j < nflexible && sumdemand <= remainingcap )
    8121 {
    8122 sumdemand += demands[j];
    8123 j++;
    8124 }
    8125
    8126 /* j jobs form a conflict, set coversize to 'j - 1' */
    8127 bigcoversize = j-1;
    8128 assert(sumdemand > remainingcap);
    8129 assert(bigcoversize < nflexible);
    8130
    8131 /* - create a row for all jobs and their binary variables.
    8132 * - at most coversize many binary variables of jobs can be set to one
    8133 */
    8134
    8135 /* construct row name */
    8136 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
    8137 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
    8138 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
    8140
    8141 for( j = 0; j < nflexible; ++j )
    8142 {
    8143 SCIP_VAR** binvars;
    8144 SCIP_Real* vals;
    8145 int nbinvars;
    8146 int idx;
    8147 int start;
    8148 int end;
    8149 int lb;
    8150 int ub;
    8151 int b;
    8152
    8153 idx = flexibleids[j];
    8154
    8155 /* get and add binvars into var array */
    8156 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
    8157 assert(nbinvars != 0);
    8158
    8159 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
    8160 assert(vals != NULL);
    8161
    8162 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
    8163 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
    8164
    8165 /* compute start and finishing time */
    8166 start = time - consdata->durations[idx] + 1;
    8167 end = MIN(time, ub);
    8168
    8169 /* add all neccessary binary variables */
    8170 for( b = 0; b < nbinvars; ++b )
    8171 {
    8172 if( vals[b] < start || vals[b] < lb )
    8173 continue;
    8174
    8175 if( vals[b] > end )
    8176 break;
    8177
    8178 assert(binvars[b] != NULL);
    8179 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
    8180 }
    8181 }
    8182
    8183 /* insert and release row */
    8185
    8186 if( consdata->bcoverrowssize == 0 )
    8187 {
    8188 consdata->bcoverrowssize = 10;
    8189 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
    8190 }
    8191 if( consdata->nbcoverrows == consdata->bcoverrowssize )
    8192 {
    8193 consdata->bcoverrowssize *= 2;
    8194 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
    8195 }
    8196
    8197 consdata->bcoverrows[consdata->nbcoverrows] = row;
    8198 consdata->nbcoverrows++;
    8199
    8200 /*
    8201 * version 2:
    8202 * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
    8203 * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
    8204 */
    8205 /* find maximum number of jobs that can run in parallel (= coversize -1) */
    8206 sumdemand = 0;
    8207 j = nflexible -1;
    8208 while( sumdemand <= remainingcap )
    8209 {
    8210 assert(j >= 0);
    8211 sumdemand += demands[j];
    8212 j--;
    8213 }
    8214
    8215 smallcoversize = nflexible - (j + 1) - 1;
    8216 while( j > 0 && demands[j] == demands[nflexible-1] )
    8217 --j;
    8218
    8219 assert(smallcoversize < nflexible);
    8220
    8221 if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
    8222 {
    8223 /* construct row name */
    8224 (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
    8225 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
    8226 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
    8228
    8229 /* filter binary variables for each unfixed job */
    8230 for( j = j + 1; j < nflexible; ++j )
    8231 {
    8232 SCIP_VAR** binvars;
    8233 SCIP_Real* vals;
    8234 int nbinvars;
    8235 int idx;
    8236 int start;
    8237 int end;
    8238 int lb;
    8239 int ub;
    8240 int b;
    8241
    8242 idx = flexibleids[j];
    8243
    8244 /* get and add binvars into var array */
    8245 SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
    8246 assert(nbinvars != 0);
    8247
    8248 vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
    8249 assert(vals != NULL);
    8250
    8251 lb = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
    8252 ub = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
    8253
    8254 /* compute start and finishing time */
    8255 start = time - consdata->durations[idx] + 1;
    8256 end = MIN(time, ub);
    8257
    8258 /* add all neccessary binary variables */
    8259 for( b = 0; b < nbinvars; ++b )
    8260 {
    8261 if( vals[b] < start || vals[b] < lb )
    8262 continue;
    8263
    8264 if( vals[b] > end )
    8265 break;
    8266
    8267 assert(binvars[b] != NULL);
    8268 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
    8269 }
    8270 }
    8271
    8272 /* insert and release row */
    8274 if( consdata->scoverrowssize == 0 )
    8275 {
    8276 consdata->scoverrowssize = 10;
    8277 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
    8278 }
    8279 if( consdata->nscoverrows == consdata->scoverrowssize )
    8280 {
    8281 consdata->scoverrowssize *= 2;
    8282 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
    8283 }
    8284
    8285 consdata->scoverrows[consdata->nscoverrows] = row;
    8286 consdata->nscoverrows++;
    8287 }
    8288
    8289 /* free buffer arrays */
    8290 SCIPfreeBufferArray(scip, &flexibleids);
    8291 SCIPfreeBufferArray(scip, &demands);
    8292
    8293 return SCIP_OKAY;
    8294}
    8295
    8296/** method to construct cover cuts for all points in time */
    8297static
    8299 SCIP* scip, /**< SCIP data structure */
    8300 SCIP_CONS* cons /**< constraint to be separated */
    8301 )
    8302{
    8303 SCIP_CONSDATA* consdata;
    8304
    8305 int* startvalues; /* stores when each job is starting */
    8306 int* endvalues; /* stores when each job ends */
    8307 int* startvaluessorted; /* stores when each job is starting */
    8308 int* endvaluessorted; /* stores when each job ends */
    8309 int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
    8310 int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
    8311
    8312 int nvars; /* number of jobs for this constraint */
    8313 int freecapacity; /* remaining capacity */
    8314 int curtime; /* point in time which we are just checking */
    8315 int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    8316
    8317 int hmin;
    8318 int hmax;
    8319
    8320 int j;
    8321 int t;
    8322
    8323 assert(scip != NULL);
    8324 assert(cons != NULL);
    8325
    8326 consdata = SCIPconsGetData(cons);
    8327 assert(consdata != NULL);
    8328
    8329 /* if no activities are associated with this resource then this constraint is redundant */
    8330 if( consdata->vars == NULL )
    8331 return SCIP_OKAY;
    8332
    8333 nvars = consdata->nvars;
    8334 hmin = consdata->hmin;
    8335 hmax = consdata->hmax;
    8336
    8337 SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
    8338 SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
    8339 SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
    8340 SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
    8341 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    8342 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    8343
    8344 /* assign start and endpoints to arrays */
    8345 for ( j = 0; j < nvars; ++j )
    8346 {
    8347 startvalues[j] = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
    8348 startvaluessorted[j] = startvalues[j];
    8349
    8350 endvalues[j] = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
    8351 endvaluessorted[j] = endvalues[j];
    8352
    8353 startindices[j] = j;
    8354 endindices[j] = j;
    8355 }
    8356
    8357 /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
    8358 * (and sort the indices in the same way) */
    8359 SCIPsortIntInt(startvaluessorted, startindices, nvars);
    8360 SCIPsortIntInt(endvaluessorted, endindices, nvars);
    8361
    8362 endidx = 0;
    8363 freecapacity = consdata->capacity;
    8364
    8365 /* check each startpoint of a job whether the capacity is kept or not */
    8366 for( j = 0; j < nvars; ++j )
    8367 {
    8368 curtime = startvaluessorted[j];
    8369 if( curtime >= hmax )
    8370 break;
    8371
    8372 /* subtract all capacity needed up to this point */
    8373 freecapacity -= consdata->demands[startindices[j]];
    8374
    8375 while( j+1 < nvars && startvaluessorted[j+1] == curtime )
    8376 {
    8377 ++j;
    8378 freecapacity -= consdata->demands[startindices[j]];
    8379 }
    8380
    8381 /* free all capacity usages of jobs the are no longer running */
    8382 while( endidx < nvars && curtime >= endvaluessorted[endidx] )
    8383 {
    8384 freecapacity += consdata->demands[endindices[endidx]];
    8385 ++endidx;
    8386 }
    8387
    8388 assert(freecapacity <= consdata->capacity);
    8389 assert(endidx <= nvars);
    8390
    8391 /* --> endindex - points to the next job which will finish
    8392 * j - points to the last job that has been released
    8393 */
    8394
    8395 /* check freecapacity to be smaller than zero
    8396 * then we will add cover constraints to the MIP
    8397 */
    8398 if( freecapacity < 0 && curtime >= hmin )
    8399 {
    8400 int nextprofilechange;
    8401
    8402 /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
    8403 if( j < nvars-1 )
    8404 nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
    8405 else
    8406 nextprofilechange = endvaluessorted[endidx];
    8407
    8408 nextprofilechange = MIN(nextprofilechange, hmax);
    8409
    8410 for( t = curtime; t < nextprofilechange; ++t )
    8411 {
    8412 SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
    8413
    8414 /* create covering constraint */
    8415 SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
    8416 }
    8417 } /* end if freecapacity > 0 */
    8418 } /*lint --e{850}*/
    8419
    8420 consdata->covercuts = TRUE;
    8421
    8422 /* free all buffer arrays */
    8423 SCIPfreeBufferArray(scip, &endindices);
    8424 SCIPfreeBufferArray(scip, &startindices);
    8425 SCIPfreeBufferArray(scip, &endvaluessorted);
    8426 SCIPfreeBufferArray(scip, &startvaluessorted);
    8427 SCIPfreeBufferArray(scip, &endvalues);
    8428 SCIPfreeBufferArray(scip, &startvalues);
    8429
    8430 return SCIP_OKAY;
    8431}
    8432
    8433/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
    8434 * constraint
    8435 */
    8436static
    8438 SCIP* scip, /**< SCIP data structure */
    8439 SCIP_CONS* cons, /**< constraint to be checked */
    8440 int* startindices, /**< permutation with rspect to the start times */
    8441 int curtime, /**< current point in time */
    8442 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    8443 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    8444 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
    8445 )
    8446{
    8447 SCIP_CONSDATA* consdata;
    8448 SCIP_VAR** binvars;
    8449 int* coefs;
    8450 int nbinvars;
    8451 char name[SCIP_MAXSTRLEN];
    8452 int capacity;
    8453 int b;
    8454
    8455 assert(nstarted > nfinished);
    8456
    8457 consdata = SCIPconsGetData(cons);
    8458 assert(consdata != NULL);
    8459 assert(consdata->nvars > 0);
    8460
    8461 capacity = consdata->capacity;
    8462 assert(capacity > 0);
    8463
    8464 nbinvars = 0;
    8465 SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
    8466
    8467 /* construct row name */
    8468 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
    8469
    8470 if( cutsasconss )
    8471 {
    8472 SCIP_CONS* lincons;
    8473
    8474 /* create knapsack constraint for the given time point */
    8475 SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
    8477
    8478 for( b = 0; b < nbinvars; ++b )
    8479 {
    8480 SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
    8481 }
    8482
    8483 /* add and release the new constraint */
    8484 SCIP_CALL( SCIPaddCons(scip, lincons) );
    8485 SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
    8486 }
    8487 else
    8488 {
    8489 SCIP_ROW* row;
    8490
    8491 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
    8493
    8494 for( b = 0; b < nbinvars; ++b )
    8495 {
    8496 SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
    8497 }
    8498
    8501
    8502 if( consdata->demandrowssize == 0 )
    8503 {
    8504 consdata->demandrowssize = 10;
    8505 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
    8506 }
    8507 if( consdata->ndemandrows == consdata->demandrowssize )
    8508 {
    8509 consdata->demandrowssize *= 2;
    8510 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
    8511 }
    8512
    8513 consdata->demandrows[consdata->ndemandrows] = row;
    8514 consdata->ndemandrows++;
    8515 }
    8516
    8517 SCIPfreeBufferArrayNull(scip, &binvars);
    8519
    8520 return SCIP_OKAY;
    8521}
    8522
    8523/** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
    8524 * row
    8525 */
    8526static
    8528 SCIP* scip, /**< SCIP data structure */
    8529 SCIP_CONS* cons, /**< constraint to be checked */
    8530 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
    8531 )
    8532{
    8533 SCIP_CONSDATA* consdata;
    8534
    8535 int* starttimes; /* stores when each job is starting */
    8536 int* endtimes; /* stores when each job ends */
    8537 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    8538 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    8539
    8540 int nvars; /* number of activities for this constraint */
    8541 int freecapacity; /* remaining capacity */
    8542 int curtime; /* point in time which we are just checking */
    8543 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    8544
    8545 int hmin;
    8546 int hmax;
    8547
    8548 int j;
    8549
    8550 assert(scip != NULL);
    8551 assert(cons != NULL);
    8552
    8553 consdata = SCIPconsGetData(cons);
    8554 assert(consdata != NULL);
    8555
    8556 nvars = consdata->nvars;
    8557
    8558 /* if no activities are associated with this cumulative then this constraint is redundant */
    8559 if( nvars == 0 )
    8560 return SCIP_OKAY;
    8561
    8562 assert(consdata->vars != NULL);
    8563
    8564 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    8565 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    8566 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    8567 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    8568
    8569 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
    8570 SCIPconsGetName(cons), nvars);
    8571
    8572 /* create event point arrays */
    8573 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
    8574 starttimes, endtimes, startindices, endindices, FALSE);
    8575
    8576 endindex = 0;
    8577 freecapacity = consdata->capacity;
    8578 hmin = consdata->hmin;
    8579 hmax = consdata->hmax;
    8580
    8581 /* check each startpoint of a job whether the capacity is kept or not */
    8582 for( j = 0; j < nvars; ++j )
    8583 {
    8584 curtime = starttimes[j];
    8585 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
    8586
    8587 if( curtime >= hmax )
    8588 break;
    8589
    8590 /* remove the capacity requirments for all job which start at the curtime */
    8591 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
    8592
    8593 /* add the capacity requirments for all job which end at the curtime */
    8594 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
    8595
    8596 assert(freecapacity <= consdata->capacity);
    8597 assert(endindex <= nvars);
    8598
    8599 /* endindex - points to the next job which will finish */
    8600 /* j - points to the last job that has been released */
    8601
    8602 /* if free capacity is smaller than zero, then add rows to the LP */
    8603 if( freecapacity < 0 && curtime >= hmin )
    8604 {
    8605 int nextstarttime;
    8606 int t;
    8607
    8608 /* step forward until next job is released and see whether capacity constraint is met or not */
    8609 if( j < nvars-1 )
    8610 nextstarttime = starttimes[j+1];
    8611 else
    8612 nextstarttime = endtimes[nvars-1];
    8613
    8614 nextstarttime = MIN(nextstarttime, hmax);
    8615
    8616 /* create capacity restriction row for current event point */
    8617 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
    8618
    8619 /* create for all points in time between the current event point and next start event point a row if the free
    8620 * capacity is still smaller than zero */
    8621 for( t = curtime+1 ; t < nextstarttime; ++t )
    8622 {
    8623 /* add the capacity requirments for all job which end at the curtime */
    8624 addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
    8625
    8626 if( freecapacity < 0 )
    8627 {
    8628 /* add constraint */
    8629 SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
    8630
    8631 /* create capacity restriction row */
    8632 SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
    8633 }
    8634 else
    8635 break;
    8636 }
    8637 }
    8638 } /*lint --e{850}*/
    8639
    8640 /* free all buffer arrays */
    8641 SCIPfreeBufferArray(scip, &endindices);
    8642 SCIPfreeBufferArray(scip, &startindices);
    8643 SCIPfreeBufferArray(scip, &endtimes);
    8644 SCIPfreeBufferArray(scip, &starttimes);
    8645
    8646 return SCIP_OKAY;
    8647}
    8648
    8649/** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
    8650 * capacity is larger than the capacity of the cumulative constraint
    8651 * - for each necessary point in time:
    8652 *
    8653 * sum_j sum_t demand_j * x_{j,t} <= capacity
    8654 *
    8655 * where x(j,t) is the binary variables of job j at time t
    8656 */
    8657static
    8659 SCIP* scip, /**< SCIP data structure */
    8660 SCIP_CONS* cons, /**< cumulative constraint */
    8661 SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
    8662 )
    8663{
    8664 SCIP_CONSDATA* consdata;
    8665
    8666 consdata = SCIPconsGetData(cons);
    8667 assert(consdata != NULL);
    8668 assert(consdata->demandrows == NULL);
    8669 assert(consdata->ndemandrows == 0);
    8670
    8671 /* collect the linking constraints */
    8672 if( consdata->linkingconss == NULL )
    8673 {
    8675 }
    8676
    8677 SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
    8678
    8679 /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
    8680 if( cutsasconss )
    8681 {
    8682 if( SCIPconsIsInitial(cons) )
    8683 {
    8685 }
    8686 if( SCIPconsIsSeparated(cons) )
    8687 {
    8689 }
    8690 if( SCIPconsIsEnforced(cons) )
    8691 {
    8693 }
    8694 }
    8695
    8696 return SCIP_OKAY;
    8697}
    8698
    8699/** adds linear relaxation of cumulative constraint to the LP */
    8700static
    8702 SCIP* scip, /**< SCIP data structure */
    8703 SCIP_CONS* cons, /**< cumulative constraint */
    8704 SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
    8705 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
    8706 )
    8707{
    8708 SCIP_CONSDATA* consdata;
    8709 int r;
    8710
    8711 consdata = SCIPconsGetData(cons);
    8712 assert(consdata != NULL);
    8713
    8714 if( consdata->demandrows == NULL )
    8715 {
    8716 assert(consdata->ndemandrows == 0);
    8717
    8718 SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
    8719
    8720 return SCIP_OKAY;
    8721 }
    8722
    8723 for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
    8724 {
    8725 if( !SCIProwIsInLP(consdata->demandrows[r]) )
    8726 {
    8727 assert(consdata->demandrows[r] != NULL);
    8728 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
    8729 }
    8730 }
    8731
    8732 return SCIP_OKAY;
    8733}
    8734
    8735/** checks constraint for violation, and adds it as a cut if possible */
    8736static
    8738 SCIP* scip, /**< SCIP data structure */
    8739 SCIP_CONS* cons, /**< cumulative constraint to be separated */
    8740 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    8741 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
    8742 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
    8743 )
    8744{ /*lint --e{715}*/
    8745 SCIP_CONSDATA* consdata;
    8746 int ncuts;
    8747 int r;
    8748
    8749 assert(scip != NULL);
    8750 assert(cons != NULL);
    8751 assert(separated != NULL);
    8752 assert(cutoff != NULL);
    8753
    8754 *separated = FALSE;
    8755 *cutoff = FALSE;
    8756
    8757 consdata = SCIPconsGetData(cons);
    8758 assert(consdata != NULL);
    8759
    8760 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
    8761
    8762 if( consdata->demandrows == NULL )
    8763 {
    8764 assert(consdata->ndemandrows == 0);
    8765
    8767
    8768 return SCIP_OKAY;
    8769 }
    8770
    8771 ncuts = 0;
    8772
    8773 /* check each row that is not contained in LP */
    8774 for( r = 0; r < consdata->ndemandrows; ++r )
    8775 {
    8776 if( !SCIProwIsInLP(consdata->demandrows[r]) )
    8777 {
    8778 SCIP_Real feasibility;
    8779
    8780 if( sol != NULL )
    8781 feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
    8782 else
    8783 feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
    8784
    8785 if( SCIPisFeasNegative(scip, feasibility) )
    8786 {
    8787 SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
    8788 if ( *cutoff )
    8789 {
    8791 return SCIP_OKAY;
    8792 }
    8793 *separated = TRUE;
    8794 ncuts++;
    8795 }
    8796 }
    8797 }
    8798
    8799 if( ncuts > 0 )
    8800 {
    8801 SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
    8802
    8803 /* if successful, reset age of constraint */
    8805 (*separated) = TRUE;
    8806 }
    8807
    8808 return SCIP_OKAY;
    8809}
    8810
    8811/** checks constraint for violation, and adds it as a cut if possible */
    8812static
    8814 SCIP* scip, /**< SCIP data structure */
    8815 SCIP_CONS* cons, /**< logic or constraint to be separated */
    8816 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    8817 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
    8818 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
    8819 )
    8820{
    8821 SCIP_CONSDATA* consdata;
    8822 SCIP_ROW* row;
    8823 SCIP_Real minfeasibility;
    8824 int r;
    8825
    8826 assert(scip != NULL);
    8827 assert(cons != NULL);
    8828 assert(separated != NULL);
    8829 assert(cutoff != NULL);
    8830
    8831 *separated = FALSE;
    8832 *cutoff = FALSE;
    8833
    8834 consdata = SCIPconsGetData(cons);
    8835 assert(consdata != NULL);
    8836
    8837 SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
    8838
    8839 /* collect the linking constraints */
    8840 if( consdata->linkingconss == NULL )
    8841 {
    8843 }
    8844
    8845 if( !consdata->covercuts )
    8846 {
    8847 SCIP_CALL( createCoverCuts(scip, cons) );
    8848 }
    8849
    8850 row = NULL;
    8851 minfeasibility = SCIPinfinity(scip);
    8852
    8853 /* check each row of small covers that is not contained in LP */
    8854 for( r = 0; r < consdata->nscoverrows; ++r )
    8855 {
    8856 if( !SCIProwIsInLP(consdata->scoverrows[r]) )
    8857 {
    8858 SCIP_Real feasibility;
    8859
    8860 assert(consdata->scoverrows[r] != NULL);
    8861 if( sol != NULL )
    8862 feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
    8863 else
    8864 feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
    8865
    8866 if( minfeasibility > feasibility )
    8867 {
    8868 minfeasibility = feasibility;
    8869 row = consdata->scoverrows[r];
    8870 }
    8871 }
    8872 }
    8873
    8874 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
    8875
    8876 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
    8877 {
    8878 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
    8879 SCIPconsGetName(cons), minfeasibility);
    8880
    8881 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    8883 if ( *cutoff )
    8884 return SCIP_OKAY;
    8885 (*separated) = TRUE;
    8886 }
    8887
    8888 minfeasibility = SCIPinfinity(scip);
    8889 row = NULL;
    8890
    8891 /* check each row of small covers that is not contained in LP */
    8892 for( r = 0; r < consdata->nbcoverrows; ++r )
    8893 {
    8894 if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
    8895 {
    8896 SCIP_Real feasibility;
    8897
    8898 assert(consdata->bcoverrows[r] != NULL);
    8899 if( sol != NULL )
    8900 feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
    8901 else
    8902 feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
    8903
    8904 if( minfeasibility > feasibility )
    8905 {
    8906 minfeasibility = feasibility;
    8907 row = consdata->bcoverrows[r];
    8908 }
    8909 }
    8910 }
    8911
    8912 assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
    8913
    8914 if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
    8915 {
    8916 SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
    8917 SCIPconsGetName(cons), minfeasibility);
    8918
    8919 assert(row != NULL);
    8920 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    8922 if ( *cutoff )
    8923 return SCIP_OKAY;
    8924 (*separated) = TRUE;
    8925 }
    8926
    8927 return SCIP_OKAY;
    8928}
    8929
    8930/** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
    8931static
    8933 SCIP* scip, /**< SCIP data structure */
    8934 SCIP_CONS* cons, /**< constraint to be checked */
    8935 int* startindices, /**< permutation with rspect to the start times */
    8936 int curtime, /**< current point in time */
    8937 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    8938 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    8939 SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
    8940 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
    8941 )
    8942{
    8943 SCIP_CONSDATA* consdata;
    8944 char name[SCIP_MAXSTRLEN];
    8945 int lhs; /* left hand side of constraint */
    8946
    8947 SCIP_VAR** activevars;
    8948 SCIP_ROW* row;
    8949
    8950 int v;
    8951
    8952 assert(nstarted > nfinished);
    8953
    8954 consdata = SCIPconsGetData(cons);
    8955 assert(consdata != NULL);
    8956 assert(consdata->nvars > 0);
    8957
    8958 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
    8959
    8960 SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
    8961
    8962 if( lower )
    8963 {
    8964 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
    8965
    8966 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
    8967 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
    8968 }
    8969 else
    8970 {
    8971 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
    8972 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
    8973 TRUE, FALSE, SCIPconsIsRemovable(cons)) );
    8974 }
    8975
    8977
    8978 for( v = 0; v < nstarted - nfinished; ++v )
    8979 {
    8980 SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
    8981 }
    8982
    8985
    8986 SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
    8987
    8988 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    8989
    8990 /* free buffers */
    8991 SCIPfreeBufferArrayNull(scip, &activevars);
    8992
    8993 return SCIP_OKAY;
    8994}
    8995
    8996/** checks constraint for violation, and adds it as a cut if possible */
    8997static
    8999 SCIP* scip, /**< SCIP data structure */
    9000 SCIP_CONS* cons, /**< cumulative constraint to be separated */
    9001 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    9002 SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
    9003 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
    9004 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
    9005 )
    9006{
    9007 SCIP_CONSDATA* consdata;
    9008
    9009 int* starttimes; /* stores when each job is starting */
    9010 int* endtimes; /* stores when each job ends */
    9011 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    9012 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    9013
    9014 int nvars; /* number of activities for this constraint */
    9015 int freecapacity; /* remaining capacity */
    9016 int curtime; /* point in time which we are just checking */
    9017 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    9018
    9019 int hmin;
    9020 int hmax;
    9021 int j;
    9022
    9023 assert(scip != NULL);
    9024 assert(cons != NULL);
    9025
    9026 consdata = SCIPconsGetData(cons);
    9027 assert(consdata != NULL);
    9028
    9029 nvars = consdata->nvars;
    9030
    9031 /* if no activities are associated with this cumulative then this constraint is redundant */
    9032 if( nvars <= 1 )
    9033 return SCIP_OKAY;
    9034
    9035 assert(consdata->vars != NULL);
    9036
    9037 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    9038 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    9039 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    9040 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    9041
    9042 SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
    9043 SCIPconsGetName(cons), nvars);
    9044
    9045 /* create event point arrays */
    9046 createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
    9047
    9048 /* now nvars might be smaller than before! */
    9049
    9050 endindex = 0;
    9051 freecapacity = consdata->capacity;
    9052 hmin = consdata->hmin;
    9053 hmax = consdata->hmax;
    9054
    9055 /* check each startpoint of a job whether the capacity is kept or not */
    9056 for( j = 0; j < nvars && !(*cutoff); ++j )
    9057 {
    9058 curtime = starttimes[j];
    9059
    9060 if( curtime >= hmax )
    9061 break;
    9062
    9063 /* remove the capacity requirements for all job which start at the curtime */
    9064 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
    9065
    9066 /* add the capacity requirments for all job which end at the curtime */
    9067 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
    9068
    9069 assert(freecapacity <= consdata->capacity);
    9070 assert(endindex <= nvars);
    9071
    9072 /* endindex - points to the next job which will finish */
    9073 /* j - points to the last job that has been released */
    9074
    9075 /* if free capacity is smaller than zero, then add rows to the LP */
    9076 if( freecapacity < 0 && curtime >= hmin)
    9077 {
    9078 /* create capacity restriction row for current event point */
    9079 SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
    9080 *separated = TRUE;
    9081 }
    9082 } /*lint --e{850}*/
    9083
    9084 /* free all buffer arrays */
    9085 SCIPfreeBufferArray(scip, &endindices);
    9086 SCIPfreeBufferArray(scip, &startindices);
    9087 SCIPfreeBufferArray(scip, &endtimes);
    9088 SCIPfreeBufferArray(scip, &starttimes);
    9089
    9090 return SCIP_OKAY;
    9091}
    9092
    9093/**@} */
    9094
    9095
    9096/**@name Presolving
    9097 *
    9098 * @{
    9099 */
    9100
    9101#ifndef NDEBUG
    9102/** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
    9103 * correct
    9104 */
    9105static
    9107 SCIP* scip, /**< SCIP data structure */
    9108 SCIP_CONS* cons /**< constraint to be checked */
    9109 )
    9110{
    9111 SCIP_CONSDATA* consdata;
    9112 int capacity;
    9113 int nvars;
    9114 int j;
    9115
    9116 assert(scip != NULL);
    9117 assert(cons != NULL);
    9118
    9119 consdata = SCIPconsGetData(cons);
    9120 assert(consdata != NULL);
    9121
    9122 nvars = consdata->nvars;
    9123
    9124 /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
    9125 if( nvars <= 1 )
    9126 return TRUE;
    9127
    9128 assert(consdata->vars != NULL);
    9129 capacity = consdata->capacity;
    9130
    9131 /* check each activity: if demand is larger than capacity the problem is infeasible */
    9132 for ( j = 0; j < nvars; ++j )
    9133 {
    9134 if( consdata->demands[j] > capacity )
    9135 return FALSE;
    9136 }
    9137
    9138 return TRUE;
    9139}
    9140#endif
    9141
    9142/** delete constraint if it consists of at most one job
    9143 *
    9144 * @todo this method needs to be adjusted w.r.t. effective horizon
    9145 */
    9146static
    9148 SCIP* scip, /**< SCIP data structure */
    9149 SCIP_CONS* cons, /**< constraint to propagate */
    9150 int* ndelconss, /**< pointer to store the number of deleted constraints */
    9151 SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
    9152 )
    9153{
    9154 SCIP_CONSDATA* consdata;
    9155
    9156 assert(scip != NULL);
    9157 assert(cons != NULL);
    9158
    9159 consdata = SCIPconsGetData(cons);
    9160 assert(consdata != NULL);
    9161
    9162 if( consdata->nvars == 0 )
    9163 {
    9164 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
    9165
    9166 SCIP_CALL( SCIPdelCons(scip, cons) );
    9167 (*ndelconss)++;
    9168 }
    9169 else if( consdata->nvars == 1 )
    9170 {
    9171 if( consdata->demands[0] > consdata->capacity )
    9172 (*cutoff) = TRUE;
    9173 else
    9174 {
    9175 SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
    9176
    9177 SCIP_CALL( SCIPdelCons(scip, cons) );
    9178 (*ndelconss)++;
    9179 }
    9180 }
    9181
    9182 return SCIP_OKAY;
    9183}
    9184
    9185/** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
    9186 * this is done in the SCIP_DECL_CONSINITPRE() callback
    9187 */
    9188static
    9190 SCIP* scip, /**< SCIP data structure */
    9191 SCIP_CONS* cons /**< constraint to propagate */
    9192 )
    9193{
    9194 SCIP_CONSDATA* consdata;
    9195 SCIP_VAR* var;
    9196 int demand;
    9197 int duration;
    9198 int hmin;
    9199 int hmax;
    9200 int est;
    9201 int lct;
    9202 int j;
    9203
    9204 assert(scip != NULL);
    9205 assert(cons != NULL);
    9206
    9207 consdata = SCIPconsGetData(cons);
    9208 assert(consdata != NULL);
    9209
    9210 hmin = consdata->hmin;
    9211 hmax = consdata->hmax;
    9212
    9213 SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
    9214 SCIPconsGetName(cons), hmin, hmax);
    9215
    9216 for( j = consdata->nvars-1; j >= 0; --j )
    9217 {
    9218 var = consdata->vars[j];
    9219 demand = consdata->demands[j];
    9220 duration = consdata->durations[j];
    9221
    9222 /* earliest completion time (ect) and latest start time (lst) */
    9224 lct = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
    9225
    9226 if( demand == 0 || duration == 0 )
    9227 {
    9228 /* jobs with zero demand or zero duration can be removed */
    9229 SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
    9230 SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
    9231
    9232 /* remove variable form constraint */
    9233 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
    9234 }
    9235 else if( est >= hmax || lct <= hmin )
    9236 {
    9237 SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
    9238 SCIPvarGetName(var), est, lct - duration, duration);
    9239
    9240 /* delete variable at the given position */
    9241 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
    9242
    9243 /* for the statistic we count the number of jobs which are irrelevant */
    9245 }
    9246 }
    9247
    9248 return SCIP_OKAY;
    9249}
    9250
    9251/** adjust bounds of over sizeed job (the demand is larger than the capacity) */
    9252static
    9254 SCIP* scip, /**< SCIP data structure */
    9255 SCIP_CONSDATA* consdata, /**< constraint data */
    9256 int pos, /**< position of job in the consdata */
    9257 int* nchgbds, /**< pointer to store the number of changed bounds */
    9258 int* naddconss, /**< pointer to store the number of added constraints */
    9259 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
    9260 )
    9261{
    9262 SCIP_VAR* var;
    9263 SCIP_Bool tightened;
    9264 int duration;
    9265 int ect;
    9266 int lst;
    9267
    9268 assert(scip != NULL);
    9269
    9270 /* zero energy jobs should be removed already */
    9271 assert(consdata->durations[pos] > 0);
    9272 assert(consdata->demands[pos] > 0);
    9273
    9274 var = consdata->vars[pos];
    9275 assert(var != NULL);
    9276 duration = consdata->durations[pos];
    9277
    9278 /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
    9279 SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
    9280 SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
    9281
    9282 /* earliest completion time (ect) and latest start time (lst) */
    9283 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
    9285
    9286 /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
    9287 if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
    9288 return SCIP_OKAY;
    9289
    9290 if( ect > consdata->hmin && lst < consdata->hmax )
    9291 {
    9292 /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
    9293 *cutoff = TRUE;
    9294 }
    9295 else if( lst < consdata->hmax )
    9296 {
    9297 /* move the latest start time of this job in such a way that it finishes before or at hmin */
    9298 SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
    9299 assert(tightened);
    9300 assert(!(*cutoff));
    9301 (*nchgbds)++;
    9302 }
    9303 else if( ect > consdata->hmin )
    9304 {
    9305 /* move the earliest start time of this job in such a way that it starts after or at hmax */
    9306 SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
    9307 assert(tightened);
    9308 assert(!(*cutoff));
    9309 (*nchgbds)++;
    9310 }
    9311 else
    9312 {
    9313 /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
    9314 * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
    9315 *
    9316 * (var <= hmin - duration) /\ (var >= hmax)
    9317 */
    9318 SCIP_CONS* cons;
    9319
    9320 SCIP_VAR* vartuple[2];
    9321 SCIP_BOUNDTYPE boundtypetuple[2];
    9322 SCIP_Real boundtuple[2];
    9323
    9324 char name[SCIP_MAXSTRLEN];
    9325 int leftbound;
    9326 int rightbound;
    9327
    9328 leftbound = consdata->hmin - duration;
    9329 rightbound = consdata->hmax;
    9330
    9331 /* allocate temporary memory for arrays */
    9332 vartuple[0] = var;
    9333 vartuple[1] = var;
    9334 boundtuple[0] = (SCIP_Real)leftbound;
    9335 boundtuple[1] = (SCIP_Real)rightbound;
    9336 boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
    9337 boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
    9338
    9339 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
    9340 SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
    9341
    9342 /* create and add bounddisjunction constraint */
    9343 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
    9344 TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
    9345
    9347
    9348 /* add and release the new constraint */
    9349 SCIP_CALL( SCIPaddCons(scip, cons) );
    9350 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    9351 (*naddconss)++;
    9352 }
    9353
    9354 return SCIP_OKAY;
    9355}
    9356
    9357/** try to removed over sizeed jobs (the demand is larger than the capacity) */
    9358static
    9360 SCIP* scip, /**< SCIP data structure */
    9361 SCIP_CONS* cons, /**< constraint */
    9362 int* nchgbds, /**< pointer to store the number of changed bounds */
    9363 int* nchgcoefs, /**< pointer to store the number of changed coefficient */
    9364 int* naddconss, /**< pointer to store the number of added constraints */
    9365 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
    9366 )
    9367{
    9368 SCIP_CONSDATA* consdata;
    9369 int capacity;
    9370 int j;
    9371
    9372 consdata = SCIPconsGetData(cons);
    9373 assert(consdata != NULL);
    9374
    9375 /* if a cutoff was already detected just return */
    9376 if( *cutoff )
    9377 return SCIP_OKAY;
    9378
    9379 capacity = consdata->capacity;
    9380
    9381 for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
    9382 {
    9383 if( consdata->demands[j] > capacity )
    9384 {
    9385 SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
    9386
    9387 /* remove variable form constraint */
    9388 SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
    9389 (*nchgcoefs)++;
    9390 }
    9391 }
    9392
    9393 SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
    9394
    9395 return SCIP_OKAY;
    9396}
    9397
    9398/** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
    9399static
    9401 SCIP* scip, /**< SCIP data structure */
    9402 SCIP_VAR* var, /**< integer variable to fix */
    9403 SCIP_Bool uplock, /**< has thet start time variable a up lock */
    9404 int* nfixedvars /**< pointer to store the number fixed variables */
    9405 )
    9406{
    9407 SCIP_Bool infeasible;
    9408 SCIP_Bool tightened;
    9409 SCIP_Bool roundable;
    9410
    9411 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
    9412 * would/could end in an implication which can lead to cutoff of the/all optimal solution
    9413 */
    9415 return SCIP_OKAY;
    9416
    9417 /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
    9418 * handler is the only one locking that variable up
    9419 */
    9420 assert(uplock == TRUE || uplock == FALSE);
    9421 assert((int)TRUE == 1); /*lint !e506*/
    9422 assert((int)FALSE == 0); /*lint !e506*/
    9423
    9424 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
    9425 return SCIP_OKAY;
    9426
    9427 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
    9428
    9429 /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
    9430 * (the transformed problem is always a minimization problem)
    9431 */
    9432 if( !roundable )
    9433 return SCIP_OKAY;
    9434
    9435 SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
    9437
    9438 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
    9439 assert(!infeasible);
    9440
    9441 if( tightened )
    9442 {
    9443 SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
    9444 (*nfixedvars)++;
    9445 }
    9446
    9447 return SCIP_OKAY;
    9448}
    9449
    9450/** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
    9451static
    9453 SCIP* scip, /**< SCIP data structure */
    9454 SCIP_VAR* var, /**< integer variable to fix */
    9455 SCIP_Bool downlock, /**< has the variable a down lock */
    9456 int* nfixedvars /**< pointer to store the number fixed variables */
    9457 )
    9458{
    9459 SCIP_Bool infeasible;
    9460 SCIP_Bool tightened;
    9461 SCIP_Bool roundable;
    9462
    9463 /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
    9464 * would/could end in an implication which can lead to cutoff of the/all optimal solution
    9465 */
    9467 return SCIP_OKAY;
    9468
    9469 /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
    9470 * handler is the only one locking that variable down
    9471 */
    9472 assert(downlock == TRUE || downlock == FALSE);
    9473 assert((int)TRUE == 1); /*lint !e506*/
    9474 assert((int)FALSE == 0); /*lint !e506*/
    9475
    9476 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
    9477 return SCIP_OKAY;
    9478
    9479 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
    9480
    9481 /* is it possible, to round variable down w.r.t. objective function? */
    9482 if( !roundable )
    9483 return SCIP_OKAY;
    9484
    9485 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
    9486 assert(!infeasible);
    9487
    9488 if( tightened )
    9489 {
    9490 SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
    9491 (*nfixedvars)++;
    9492 }
    9493
    9494 return SCIP_OKAY;
    9495}
    9496
    9497/** normalize cumulative condition */
    9498static
    9500 SCIP* scip, /**< SCIP data structure */
    9501 int nvars, /**< number of start time variables (activities) */
    9502 int* demands, /**< array of demands */
    9503 int* capacity, /**< pointer to store the changed cumulative capacity */
    9504 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    9505 int* nchgsides /**< pointer to count number of side changes */
    9506 )
    9507{ /*lint --e{715}*/
    9508 SCIP_Longint gcd;
    9509 int mindemand1;
    9510 int mindemand2;
    9511 int v;
    9512
    9513 if( *capacity == 1 || nvars <= 1 )
    9514 return;
    9515
    9516 assert(demands[nvars-1] <= *capacity);
    9517 assert(demands[nvars-2] <= *capacity);
    9518
    9519 gcd = (SCIP_Longint)demands[nvars-1];
    9520 mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
    9521 mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
    9522
    9523 for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
    9524 {
    9525 assert(mindemand1 <= mindemand2);
    9526 assert(demands[v] <= *capacity);
    9527
    9528 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
    9529
    9530 if( mindemand1 > demands[v] )
    9531 {
    9532 mindemand2 = mindemand1;
    9533 mindemand1 = demands[v];
    9534 }
    9535 else if( mindemand2 > demands[v] )
    9536 mindemand2 = demands[v];
    9537 }
    9538
    9539 if( mindemand1 + mindemand2 > *capacity )
    9540 {
    9541 SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
    9542
    9543 for( v = 0; v < nvars; ++v )
    9544 demands[v] = 1;
    9545
    9546 (*capacity) = 1;
    9547
    9548 (*nchgcoefs) += nvars;
    9549 (*nchgsides)++;
    9550 }
    9551 else if( gcd >= 2 )
    9552 {
    9553 SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
    9554
    9555 for( v = 0; v < nvars; ++v )
    9556 demands[v] /= (int) gcd;
    9557
    9558 (*capacity) /= (int) gcd;
    9559
    9560 (*nchgcoefs) += nvars;
    9561 (*nchgsides)++;
    9562 }
    9563}
    9564
    9565/** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
    9566 * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
    9567 * capacity since in that case none of the jobs can run in parallel
    9568 */
    9569static
    9571 SCIP* scip, /**< SCIP data structure */
    9572 SCIP_CONS* cons, /**< cumulative constraint */
    9573 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    9574 int* nchgsides /**< pointer to count number of side changes */
    9575 )
    9576{
    9577 SCIP_CONSDATA* consdata;
    9578 int capacity;
    9579
    9580 assert(nchgcoefs != NULL);
    9581 assert(nchgsides != NULL);
    9582 assert(!SCIPconsIsModifiable(cons));
    9583
    9584 consdata = SCIPconsGetData(cons);
    9585 assert(consdata != NULL);
    9586
    9587 if( consdata->normalized )
    9588 return;
    9589
    9590 capacity = consdata->capacity;
    9591
    9592 /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
    9593
    9594 normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
    9595
    9596 consdata->normalized = TRUE;
    9597
    9598 if( capacity > consdata->capacity )
    9599 consdata->varbounds = FALSE;
    9600}
    9601
    9602/** computes for the given cumulative condition the effective horizon */
    9603static
    9605 SCIP* scip, /**< SCIP data structure */
    9606 int nvars, /**< number of variables (jobs) */
    9607 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    9608 int* durations, /**< array containing corresponding durations */
    9609 int* demands, /**< array containing corresponding demands */
    9610 int capacity, /**< available cumulative capacity */
    9611 int* hmin, /**< pointer to store the left bound of the effective horizon */
    9612 int* hmax, /**< pointer to store the right bound of the effective horizon */
    9613 int* split /**< point were the cumulative condition can be split */
    9614 )
    9615{
    9616 SCIP_PROFILE* profile;
    9617
    9618 /* create empty resource profile with infinity resource capacity */
    9619 SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
    9620
    9621 /* create worst case resource profile */
    9622 SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
    9623
    9624 /* print resource profile in if SCIP_DEBUG is defined */
    9626
    9627 /* computes the first time point where the resource capacity can be violated */
    9628 (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
    9629
    9630 /* computes the first time point where the resource capacity is satisfied for sure */
    9631 (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
    9632
    9633 (*split) = (*hmax);
    9634
    9635 if( *hmin < *hmax && !SCIPinRepropagation(scip) )
    9636 {
    9637 int* timepoints;
    9638 int* loads;
    9639 int ntimepoints;
    9640 int t;
    9641
    9642 /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
    9643 * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
    9644 * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
    9645 * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
    9646 * explain the certain "old" bound changes
    9647 */
    9648
    9649 /* search for time points */
    9650 ntimepoints = SCIPprofileGetNTimepoints(profile);
    9651 timepoints = SCIPprofileGetTimepoints(profile);
    9652 loads = SCIPprofileGetLoads(profile);
    9653
    9654 /* 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 */
    9655 for( t = 0; t < ntimepoints; ++t )
    9656 {
    9657 /* ignore all time points before the effective horizon */
    9658 if( timepoints[t] <= *hmin )
    9659 continue;
    9660
    9661 /* ignore all time points after the effective horizon */
    9662 if( timepoints[t] >= *hmax )
    9663 break;
    9664
    9665 /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
    9666 * can split the cumulative constraint into two cumulative constraints
    9667 */
    9668 if( loads[t] <= capacity )
    9669 {
    9670 (*split) = timepoints[t];
    9671 break;
    9672 }
    9673 }
    9674 }
    9675
    9676 /* free worst case profile */
    9677 SCIPprofileFree(&profile);
    9678
    9679 return SCIP_OKAY;
    9680}
    9681
    9682/** creates and adds a cumulative constraint */
    9683static
    9685 SCIP* scip, /**< SCIP data structure */
    9686 const char* name, /**< name of constraint */
    9687 int nvars, /**< number of variables (jobs) */
    9688 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    9689 int* durations, /**< array containing corresponding durations */
    9690 int* demands, /**< array containing corresponding demands */
    9691 int capacity, /**< available cumulative capacity */
    9692 int hmin, /**< left bound of time axis to be considered (including hmin) */
    9693 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    9694 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    9695 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    9696 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    9697 * Usually set to TRUE. */
    9698 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    9699 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    9700 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    9701 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    9702 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    9703 * Usually set to TRUE. */
    9704 SCIP_Bool local, /**< is constraint only valid locally?
    9705 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    9706 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    9707 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    9708 * adds coefficients to this constraint. */
    9709 SCIP_Bool dynamic, /**< is constraint subject to aging?
    9710 * Usually set to FALSE. Set to TRUE for own cuts which
    9711 * are seperated as constraints. */
    9712 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    9713 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    9714 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    9715 * if it may be moved to a more global node?
    9716 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    9717 )
    9718{
    9719 SCIP_CONS* cons;
    9720
    9721 /* creates cumulative constraint and adds it to problem */
    9722 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
    9723 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    9724
    9725 /* adjust the effective time horizon of the new constraint */
    9726 SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
    9727 SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
    9728
    9729 /* add and release new cumulative constraint */
    9730 SCIP_CALL( SCIPaddCons(scip, cons) );
    9731 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    9732
    9733 return SCIP_OKAY;
    9734}
    9735
    9736/** computes the effective horizon and checks if the constraint can be decompsed */
    9737static
    9739 SCIP* scip, /**< SCIP data structure */
    9740 SCIP_CONS* cons, /**< cumulative constraint */
    9741 int* ndelconss, /**< pointer to store the number of deleted constraints */
    9742 int* naddconss, /**< pointer to store the number of added constraints */
    9743 int* nchgsides /**< pointer to store the number of changed sides */
    9744 )
    9745{
    9746 SCIP_CONSDATA* consdata;
    9747 int hmin;
    9748 int hmax;
    9749 int split;
    9750
    9751 consdata = SCIPconsGetData(cons);
    9752 assert(consdata != NULL);
    9753
    9754 if( consdata->nvars <= 1 )
    9755 return SCIP_OKAY;
    9756
    9757 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
    9758 consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
    9759
    9760 /* check if this time point improves the effective horizon */
    9761 if( consdata->hmin < hmin )
    9762 {
    9763 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
    9764
    9765 consdata->hmin = hmin;
    9766 (*nchgsides)++;
    9767 }
    9768
    9769 /* check if this time point improves the effective horizon */
    9770 if( consdata->hmax > hmax )
    9771 {
    9772 SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
    9773 consdata->hmax = hmax;
    9774 (*nchgsides)++;
    9775 }
    9776
    9777 /* check if the constraint is redundant */
    9778 if( consdata->hmax <= consdata->hmin )
    9779 {
    9780 SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
    9781 SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
    9782
    9783 SCIP_CALL( SCIPdelCons(scip, cons) );
    9784 (*ndelconss)++;
    9785 }
    9786 else if( consdata->hmin < split && split < consdata->hmax )
    9787 {
    9788 char name[SCIP_MAXSTRLEN];
    9789 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
    9790
    9791 SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
    9792 SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
    9793
    9794 assert(split < consdata->hmax);
    9795
    9796 /* creates cumulative constraint and adds it to problem */
    9797 SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
    9798 consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
    9801
    9802 /* adjust the effective time horizon of the constraint */
    9803 consdata->hmax = split;
    9804
    9805 assert(consdata->hmin < consdata->hmax);
    9806
    9807 /* for the statistic we count the number of time we decompose a cumulative constraint */
    9809 (*naddconss)++;
    9810 }
    9811
    9812 return SCIP_OKAY;
    9813}
    9814
    9815
    9816/** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
    9817 *
    9818 * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
    9819 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
    9820 *
    9821 * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
    9822 * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
    9823 * down-lock of the corresponding start time variable can be removed.
    9824 *
    9825 * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
    9826 * locking the corresponding variable down, and the objective coefficient of the start time variable is not
    9827 * negative, than the job can be dual fixed to its earlier start time (est).
    9828 *
    9829 * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
    9830 * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
    9831 * removing the values {est+1,...,hmin} form variable domain is dual feasible.
    9832 *
    9833 * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
    9834 * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
    9835 * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
    9836 * form variable domain is dual feasible.
    9837 *
    9838 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
    9839 * the cumulative condition; The deletion has to be done later.
    9840 */
    9841static
    9843 SCIP* scip, /**< SCIP data structure */
    9844 int nvars, /**< number of start time variables (activities) */
    9845 SCIP_VAR** vars, /**< array of start time variables */
    9846 int* durations, /**< array of durations */
    9847 int hmin, /**< left bound of time axis to be considered (including hmin) */
    9848 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    9849 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
    9850 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
    9851 SCIP_CONS* cons, /**< underlying constraint, or NULL */
    9852 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
    9853 int* nfixedvars, /**< pointer to store the number of fixed variables */
    9854 int* nchgsides, /**< pointer to store the number of changed sides */
    9855 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    9856 )
    9857{
    9858 SCIP_Real* downimpllbs;
    9859 SCIP_Real* downimplubs;
    9860 SCIP_Real* downproplbs;
    9861 SCIP_Real* downpropubs;
    9862 SCIP_Real* upimpllbs;
    9863 SCIP_Real* upimplubs;
    9864 SCIP_Real* upproplbs;
    9865 SCIP_Real* uppropubs;
    9866
    9867 int firstminect;
    9868 int secondminect;
    9869 int v;
    9870
    9871 /* get temporary memory for storing probing results needed for step (4) and (5) */
    9872 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
    9873 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
    9874 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
    9875 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
    9876 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
    9877 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
    9878 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
    9879 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
    9880
    9881 assert(scip != NULL);
    9882 assert(nvars > 1);
    9883 assert(cons != NULL);
    9884
    9885 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
    9886
    9887 firstminect = INT_MAX;
    9888 secondminect = INT_MAX;
    9889
    9890 /* compute the two smallest earlier completion times; which are needed for step (5) */
    9891 for( v = 0; v < nvars; ++v )
    9892 {
    9893 int ect;
    9894
    9895 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
    9896
    9897 if( ect < firstminect )
    9898 {
    9899 secondminect = firstminect;
    9900 firstminect = ect;
    9901 }
    9902 else if( ect < secondminect )
    9903 secondminect = ect;
    9904 }
    9905
    9906 /* loop over all jobs and check if one of the 5 reductions can be applied */
    9907 for( v = 0; v < nvars; ++v )
    9908 {
    9909 SCIP_VAR* var;
    9910 int duration;
    9911
    9912 int alternativelb;
    9913 int minect;
    9914 int est;
    9915 int ect;
    9916 int lst;
    9917 int lct;
    9918
    9919 var = vars[v];
    9920 assert(var != NULL);
    9921
    9922 duration = durations[v];
    9923 assert(duration > 0);
    9924
    9925 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
    9926 * time (lct)
    9927 */
    9929 ect = est + duration;
    9931 lct = lst + duration;
    9932
    9933 /* compute the earliest completion time of all remaining jobs */
    9934 if( ect == firstminect )
    9935 minect = secondminect;
    9936 else
    9937 minect = firstminect;
    9938
    9939 /* compute potential alternative lower bound (step (4) and (5)) */
    9940 alternativelb = MAX(hmin+1, minect);
    9941 alternativelb = MIN(alternativelb, hmax);
    9942
    9943 if( lct <= hmin )
    9944 {
    9945 /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
    9946 * cumulative condition
    9947 */
    9948 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
    9949 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
    9950
    9951 /* mark variable to be irrelevant */
    9952 irrelevants[v] = TRUE;
    9953
    9954 /* for the statistic we count the number of jobs which are irrelevant */
    9956 }
    9957 else if( lst <= hmin && SCIPconsIsChecked(cons) )
    9958 {
    9959 /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
    9960 * so the down lock can be omitted
    9961 */
    9962
    9963 assert(downlocks != NULL);
    9964 assert(uplocks != NULL);
    9965
    9966 if( !uplocks[v] )
    9967 {
    9968 /* the variables has no up lock and we can also remove the down lock;
    9969 * => lst <= hmin and ect >= hmax
    9970 * => remove job and reduce capacity by the demand of that job
    9971 *
    9972 * We mark the job to be deletable. The removement together with the capacity reducion is done later
    9973 */
    9974
    9975 SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
    9976 SCIPvarGetName(var), ect - duration, lst, duration);
    9977
    9978 /* mark variable to be irrelevant */
    9979 irrelevants[v] = TRUE;
    9980
    9981 /* for the statistic we count the number of jobs which always run during the effective horizon */
    9983 }
    9984
    9985 if( downlocks[v] )
    9986 {
    9987 SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
    9988 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
    9989
    9990 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
    9991 downlocks[v] = FALSE;
    9992 (*nchgsides)++;
    9993
    9994 /* for the statistic we count the number of removed locks */
    9996 }
    9997 }
    9998 else if( ect <= hmin )
    9999 {
    10000 /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
    10001 * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
    10002 * removed form the cumulative condition after it was fixed to its earliest start time
    10003 */
    10004
    10005 /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
    10006 * bound;
    10007 */
    10008 if( downlocks != NULL && SCIPconsIsChecked(cons) )
    10009 {
    10010 /* fix integer start time variable if possible to it lower bound */
    10011 SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
    10012 }
    10013
    10014 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
    10015 {
    10016 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
    10017 SCIPvarGetName(var), ect - duration, lst, duration);
    10018
    10019 /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
    10020 assert(boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
    10021
    10022 /* mark variable to be irrelevant */
    10023 irrelevants[v] = TRUE;
    10024
    10025 /* for the statistic we count the number of jobs which are dual fixed */
    10027 }
    10028 }
    10029 else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
    10030 {
    10031 assert(downlocks != NULL);
    10032
    10033 /* check step (4) and (5) */
    10034
    10035 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
    10036 * is in favor of rounding the variable down
    10037 */
    10038 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
    10039 {
    10040 SCIP_Bool roundable;
    10041
    10042 SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
    10043
    10044 if( roundable )
    10045 {
    10046 if( alternativelb > lst )
    10047 {
    10048 SCIP_Bool infeasible;
    10049 SCIP_Bool fixed;
    10050
    10051 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
    10052 assert(!infeasible);
    10053 assert(fixed);
    10054
    10055 (*nfixedvars)++;
    10056
    10057 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
    10058 * constraints
    10059 */
    10061 }
    10062 else
    10063 {
    10064 SCIP_Bool success;
    10065
    10066 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
    10067 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
    10068 * infeasible we can apply the dual reduction; otherwise we do nothing
    10069 */
    10070 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
    10071 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
    10072 nfixedvars, &success, cutoff) );
    10073
    10074 if( success )
    10075 {
    10077 }
    10078 }
    10079 }
    10080 }
    10081 }
    10082
    10083 SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
    10084 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
    10085 }
    10086
    10087 /* free temporary memory */
    10088 SCIPfreeBufferArray(scip, &uppropubs);
    10089 SCIPfreeBufferArray(scip, &upproplbs);
    10090 SCIPfreeBufferArray(scip, &upimplubs);
    10091 SCIPfreeBufferArray(scip, &upimpllbs);
    10092 SCIPfreeBufferArray(scip, &downpropubs);
    10093 SCIPfreeBufferArray(scip, &downproplbs);
    10094 SCIPfreeBufferArray(scip, &downimplubs);
    10095 SCIPfreeBufferArray(scip, &downimpllbs);
    10096
    10097 return SCIP_OKAY;
    10098}
    10099
    10100/** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
    10101 *
    10102 * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
    10103 * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
    10104 *
    10105 * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
    10106 * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
    10107 * up-lock of the corresponding start time variable can be removed.
    10108 *
    10109 * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
    10110 * locking the corresponding variable up, and the objective coefficient of the start time variable is not
    10111 * positive, than the job can be dual fixed to its latest start time (lst).
    10112 *
    10113 * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
    10114 * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
    10115 * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
    10116 * of the corresponding job).
    10117
    10118 * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
    10119 * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
    10120 * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
    10121 * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
    10122 *
    10123 * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
    10124 * the cumulative condition; The deletion has to be done later.
    10125 */
    10126static
    10128 SCIP* scip, /**< SCIP data structure */
    10129 int nvars, /**< number of start time variables (activities) */
    10130 SCIP_VAR** vars, /**< array of start time variables */
    10131 int* durations, /**< array of durations */
    10132 int hmin, /**< left bound of time axis to be considered (including hmin) */
    10133 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    10134 SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
    10135 SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
    10136 SCIP_CONS* cons, /**< underlying constraint, or NULL */
    10137 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
    10138 int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
    10139 int* nchgsides, /**< pointer to store the number of changed sides */
    10140 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    10141 )
    10142{
    10143 SCIP_Real* downimpllbs;
    10144 SCIP_Real* downimplubs;
    10145 SCIP_Real* downproplbs;
    10146 SCIP_Real* downpropubs;
    10147 SCIP_Real* upimpllbs;
    10148 SCIP_Real* upimplubs;
    10149 SCIP_Real* upproplbs;
    10150 SCIP_Real* uppropubs;
    10151
    10152 int firstmaxlst;
    10153 int secondmaxlst;
    10154 int v;
    10155
    10156 /* get temporary memory for storing probing results needed for step (4) and (5) */
    10157 SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
    10158 SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
    10159 SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
    10160 SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
    10161 SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
    10162 SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
    10163 SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
    10164 SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
    10165
    10166 assert(scip != NULL);
    10167 assert(nvars > 1);
    10168 assert(cons != NULL);
    10169
    10170 SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
    10171
    10172 firstmaxlst = INT_MIN;
    10173 secondmaxlst = INT_MIN;
    10174
    10175 /* compute the two largest latest start times; which are needed for step (5) */
    10176 for( v = 0; v < nvars; ++v )
    10177 {
    10178 int lst;
    10179
    10181
    10182 if( lst > firstmaxlst )
    10183 {
    10184 secondmaxlst = firstmaxlst;
    10185 firstmaxlst = lst;
    10186 }
    10187 else if( lst > secondmaxlst )
    10188 secondmaxlst = lst;
    10189 }
    10190
    10191 /* loop over all jobs and check if one of the 5 reductions can be applied */
    10192 for( v = 0; v < nvars; ++v )
    10193 {
    10194 SCIP_VAR* var;
    10195 int duration;
    10196
    10197 int alternativeub;
    10198 int maxlst;
    10199 int est;
    10200 int ect;
    10201 int lst;
    10202
    10203 var = vars[v];
    10204 assert(var != NULL);
    10205
    10206 duration = durations[v];
    10207 assert(duration > 0);
    10208
    10209 /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
    10210 * time (lct)
    10211 */
    10213 ect = est + duration;
    10215
    10216 /* compute the latest start time of all remaining jobs */
    10217 if( lst == firstmaxlst )
    10218 maxlst = secondmaxlst;
    10219 else
    10220 maxlst = firstmaxlst;
    10221
    10222 /* compute potential alternative upper bound (step (4) and (5)) */
    10223 alternativeub = MIN(hmax - 1, maxlst) - duration;
    10224 alternativeub = MAX(alternativeub, hmin);
    10225
    10226 if( est >= hmax )
    10227 {
    10228 /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
    10229 * cumulative condition
    10230 */
    10231 SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
    10232 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
    10233
    10234 /* mark variable to be irrelevant */
    10235 irrelevants[v] = TRUE;
    10236
    10237 /* for the statistic we count the number of jobs which are irrelevant */
    10239 }
    10240 else if( ect >= hmax && SCIPconsIsChecked(cons) )
    10241 {
    10242 assert(downlocks != NULL);
    10243 assert(uplocks != NULL);
    10244
    10245 /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
    10246 * so the up lock can be omitted
    10247 */
    10248
    10249 if( !downlocks[v] )
    10250 {
    10251 /* the variables has no down lock and we can also remove the up lock;
    10252 * => lst <= hmin and ect >= hmax
    10253 * => remove job and reduce capacity by the demand of that job
    10254 */
    10255 SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
    10256 SCIPvarGetName(var), est, lst, duration);
    10257
    10258 /* mark variable to be irrelevant */
    10259 irrelevants[v] = TRUE;
    10260
    10261 /* for the statistic we count the number of jobs which always run during the effective horizon */
    10263 }
    10264
    10265 if( uplocks[v] )
    10266 {
    10267 SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
    10268 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
    10269
    10270 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
    10271 uplocks[v] = FALSE;
    10272 (*nchgsides)++;
    10273
    10274 /* for the statistic we count the number of removed locks */
    10276 }
    10277 }
    10278 else if( lst >= hmax )
    10279 {
    10280 /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
    10281 * latest start time (which implies that it starts after the effective horizon finishes), the job can be
    10282 * removed form the cumulative condition after it was fixed to its latest start time
    10283 */
    10284
    10285 /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
    10286 * bound
    10287 */
    10288 if( uplocks != NULL && SCIPconsIsChecked(cons) )
    10289 {
    10290 /* fix integer start time variable if possible to its upper bound */
    10291 SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
    10292 }
    10293
    10294 if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
    10295 {
    10296 SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
    10297 SCIPvarGetName(var), est, lst, duration);
    10298
    10299 /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
    10300 assert(boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
    10301
    10302 /* mark variable to be irrelevant */
    10303 irrelevants[v] = TRUE;
    10304
    10305 /* for the statistic we count the number of jobs which are dual fixed */
    10307 }
    10308 }
    10309 else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
    10310 {
    10311 assert(uplocks != NULL);
    10312
    10313 /* check step (4) and (5) */
    10314
    10315 /* check if the cumulative constraint is the only one looking this variable down and if the objective function
    10316 * is in favor of rounding the variable down
    10317 */
    10318 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
    10319 {
    10320 SCIP_Bool roundable;
    10321
    10322 SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
    10323
    10324 if( roundable )
    10325 {
    10326 if( alternativeub < est )
    10327 {
    10328 SCIP_Bool infeasible;
    10329 SCIP_Bool fixed;
    10330
    10331 SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
    10332 assert(!infeasible);
    10333 assert(fixed);
    10334
    10335 (*nfixedvars)++;
    10336
    10337 /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
    10338 * constraints
    10339 */
    10341 }
    10342 else
    10343 {
    10344 SCIP_Bool success;
    10345
    10346 /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
    10347 * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
    10348 * in infeasible we can apply the dual reduction; otherwise we do nothing
    10349 */
    10350 SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
    10351 downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
    10352 nfixedvars, &success, cutoff) );
    10353
    10354 if( success )
    10355 {
    10357 }
    10358 }
    10359 }
    10360 }
    10361 }
    10362 }
    10363
    10364 /* free temporary memory */
    10365 SCIPfreeBufferArray(scip, &uppropubs);
    10366 SCIPfreeBufferArray(scip, &upproplbs);
    10367 SCIPfreeBufferArray(scip, &upimplubs);
    10368 SCIPfreeBufferArray(scip, &upimpllbs);
    10369 SCIPfreeBufferArray(scip, &downpropubs);
    10370 SCIPfreeBufferArray(scip, &downproplbs);
    10371 SCIPfreeBufferArray(scip, &downimplubs);
    10372 SCIPfreeBufferArray(scip, &downimpllbs);
    10373
    10374 return SCIP_OKAY;
    10375}
    10376
    10377/** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
    10378static
    10380 SCIP* scip, /**< SCIP data structure */
    10381 SCIP_CONS* cons, /**< cumulative constraint */
    10382 int* nfixedvars, /**< pointer to store the number of fixed variables */
    10383 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
    10384 int* nchgsides, /**< pointer to store the number of changed sides */
    10385 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
    10386 )
    10387{
    10388 SCIP_CONSDATA* consdata;
    10389 SCIP_Bool* irrelevants;
    10390 int nvars;
    10391 int v;
    10392
    10393 assert(scip != NULL);
    10394 assert(cons != NULL);
    10395 assert(!(*cutoff));
    10396
    10397 consdata = SCIPconsGetData(cons);
    10398 assert(consdata != NULL);
    10399
    10400 nvars = consdata->nvars;
    10401
    10402 if( nvars <= 1 )
    10403 return SCIP_OKAY;
    10404
    10405 SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
    10406 BMSclearMemoryArray(irrelevants, nvars);
    10407
    10408 /* presolve constraint form the earlier start time point of view */
    10409 SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
    10410 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
    10411 irrelevants, nfixedvars, nchgsides, cutoff) );
    10412
    10413 /* presolve constraint form the latest completion time point of view */
    10414 SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
    10415 consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
    10416 irrelevants, nfixedvars, nchgsides, cutoff) );
    10417
    10418 /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
    10419 * order to ensure a correct behaviour
    10420 */
    10421 for( v = nvars-1; v >= 0; --v )
    10422 {
    10423 if( irrelevants[v] )
    10424 {
    10425 SCIP_VAR* var;
    10426 int ect;
    10427 int lst;
    10428
    10429 var = consdata->vars[v];
    10430 assert(var != NULL);
    10431
    10432 ect = boundedConvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
    10434
    10435 /* check if the jobs runs completely during the effective horizon */
    10436 if( lst <= consdata->hmin && ect >= consdata->hmax )
    10437 {
    10438 if( consdata->capacity < consdata->demands[v] )
    10439 {
    10440 *cutoff = TRUE;
    10441 break;
    10442 }
    10443
    10444 consdata->capacity -= consdata->demands[v];
    10445 consdata->varbounds = FALSE;
    10446 }
    10447
    10448 SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
    10449 (*nchgcoefs)++;
    10450 }
    10451 }
    10452
    10453 SCIPfreeBufferArray(scip, &irrelevants);
    10454
    10455 return SCIP_OKAY;
    10456}
    10457
    10458/** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
    10459static
    10461 SCIP* scip, /**< SCIP data structure */
    10462 SCIP_CONSDATA* consdata, /**< constraint data */
    10463 int* startindices, /**< permutation with rspect to the start times */
    10464 int curtime, /**< current point in time */
    10465 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    10466 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    10467 SCIP_Longint** demands, /**< pointer to array storing the demands */
    10468 int* ndemands /**< pointer to store the number of different demands */
    10469 )
    10470{
    10471 int startindex;
    10472 int ncountedvars;
    10473
    10474 assert(demands != NULL);
    10475 assert(ndemands != NULL);
    10476
    10477 ncountedvars = 0;
    10478 startindex = nstarted - 1;
    10479
    10480 *ndemands = 0;
    10481
    10482 /* search for the (nstarted - nfinished) jobs which are active at curtime */
    10483 while( nstarted - nfinished > ncountedvars )
    10484 {
    10485 SCIP_VAR* var;
    10486 int endtime;
    10487 int varidx;
    10488
    10489 /* collect job information */
    10490 varidx = startindices[startindex];
    10491 assert(varidx >= 0 && varidx < consdata->nvars);
    10492
    10493 var = consdata->vars[varidx];
    10494 assert(var != NULL);
    10495
    10496 endtime = boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
    10497
    10498 /* check the end time of this job is larger than the curtime; in this case the job is still running */
    10499 if( endtime > curtime )
    10500 {
    10501 if( consdata->demands[varidx] < consdata->capacity )
    10502 {
    10503 (*demands)[*ndemands] = consdata->demands[varidx];
    10504 (*ndemands)++;
    10505 }
    10506 ncountedvars++;
    10507 }
    10508
    10509 startindex--;
    10510 }
    10511}
    10512
    10513/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
    10514 * constraint
    10515 */
    10516static
    10518 SCIP* scip, /**< SCIP data structure */
    10519 SCIP_CONS* cons, /**< constraint to be checked */
    10520 int* startindices, /**< permutation with rspect to the start times */
    10521 int curtime, /**< current point in time */
    10522 int nstarted, /**< number of jobs that start before the curtime or at curtime */
    10523 int nfinished, /**< number of jobs that finished before curtime or at curtime */
    10524 int* bestcapacity /**< pointer to store the maximum possible capacity usage */
    10525 )
    10526{
    10527 SCIP_CONSDATA* consdata;
    10528 SCIP_Longint* demands;
    10529 SCIP_Real* profits;
    10530 int* items;
    10531 int ndemands;
    10532 SCIP_Bool success;
    10533 SCIP_Real solval;
    10534 int j;
    10535 assert(nstarted > nfinished);
    10536
    10537 consdata = SCIPconsGetData(cons);
    10538 assert(consdata != NULL);
    10539 assert(consdata->nvars > 0);
    10540 assert(consdata->capacity > 0);
    10541
    10542 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
    10543 ndemands = 0;
    10544
    10545 /* get demand array to initialize knapsack problem */
    10546 collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
    10547
    10548 /* create array for profits */
    10549 SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
    10550 SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
    10551 for( j = 0; j < ndemands; ++j )
    10552 {
    10553 profits[j] = (SCIP_Real) demands[j];
    10554 items[j] = j;/* this is only a dummy value*/
    10555 }
    10556
    10557 /* solve knapsack problem and get maximum capacity usage <= capacity */
    10558 SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
    10559 items, NULL, NULL, NULL, NULL, &solval, &success) );
    10560
    10561 assert(SCIPisFeasIntegral(scip, solval));
    10562
    10563 /* store result */
    10564 *bestcapacity = boundedConvertRealToInt(scip, solval);
    10565
    10566 SCIPfreeBufferArray(scip, &items);
    10567 SCIPfreeBufferArray(scip, &profits);
    10568 SCIPfreeBufferArray(scip, &demands);
    10569
    10570 return SCIP_OKAY;
    10571}
    10572
    10573/** try to tighten the capacity
    10574 * -- using DP for knapsack, we find the maximum possible capacity usage
    10575 * -- neglects hmin and hmax, such that it is also able to check solutions globally
    10576 */
    10577static
    10579 SCIP* scip, /**< SCIP data structure */
    10580 SCIP_CONS* cons, /**< cumulative constraint */
    10581 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    10582 int* nchgsides /**< pointer to store the number of changed sides */
    10583 )
    10584{
    10585 SCIP_CONSDATA* consdata;
    10586 int* starttimes; /* stores when each job is starting */
    10587 int* endtimes; /* stores when each job ends */
    10588 int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
    10589 int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
    10590
    10591 int nvars; /* number of activities for this constraint */
    10592 int freecapacity; /* remaining capacity */
    10593 int curtime; /* point in time which we are just checking */
    10594 int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
    10595
    10596 int bestcapacity;
    10597
    10598 int j;
    10599
    10600 assert(scip != NULL);
    10601 assert(cons != NULL);
    10602 assert(nchgsides != NULL);
    10603
    10604 consdata = SCIPconsGetData(cons);
    10605 assert(consdata != NULL);
    10606
    10607 nvars = consdata->nvars;
    10608
    10609 /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
    10610 if( nvars <= 1 || consdata->capacity <= 1 )
    10611 return SCIP_OKAY;
    10612
    10613 assert(consdata->vars != NULL);
    10614
    10615 SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
    10616 SCIPconsGetName(cons), consdata->capacity);
    10617
    10618 SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
    10619 SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
    10620 SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
    10621 SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
    10622
    10623 /* create event point arrays */
    10624 createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
    10625 starttimes, endtimes, startindices, endindices, FALSE);
    10626
    10627 bestcapacity = 1;
    10628 endindex = 0;
    10629 freecapacity = consdata->capacity;
    10630
    10631 /* check each startpoint of a job whether the capacity is kept or not */
    10632 for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
    10633 {
    10634 curtime = starttimes[j];
    10635 SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
    10636
    10637 /* remove the capacity requirments for all job which start at the curtime */
    10638 subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
    10639
    10640 /* add the capacity requirments for all job which end at the curtime */
    10641 addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
    10642
    10643 assert(freecapacity <= consdata->capacity);
    10644 assert(endindex <= nvars);
    10645
    10646 /* endindex - points to the next job which will finish */
    10647 /* j - points to the last job that has been released */
    10648
    10649 /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
    10650 if( freecapacity < 0 )
    10651 {
    10652 int newcapacity;
    10653
    10654 newcapacity = 1;
    10655
    10656 /* get best possible upper bound on capacity usage */
    10657 SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
    10658
    10659 /* update bestcapacity */
    10660 bestcapacity = MAX(bestcapacity, newcapacity);
    10661 SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
    10662 }
    10663
    10664 /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
    10665 if( freecapacity > 0 && freecapacity != consdata->capacity )
    10666 {
    10667 bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
    10668 SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
    10669 }
    10670
    10671 /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
    10672 if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
    10673 {
    10674 /* if demands[startindices[j]] == cap then exactly that job is running */
    10675 SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
    10676 bestcapacity = consdata->capacity;
    10677 break;
    10678 }
    10679 } /*lint --e{850}*/
    10680
    10681 /* free all buffer arrays */
    10682 SCIPfreeBufferArray(scip, &endindices);
    10683 SCIPfreeBufferArray(scip, &startindices);
    10684 SCIPfreeBufferArray(scip, &endtimes);
    10685 SCIPfreeBufferArray(scip, &starttimes);
    10686
    10687 /* check whether capacity can be tightened and whether demands need to be adjusted */
    10688 if( bestcapacity < consdata->capacity )
    10689 {
    10690 SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
    10691
    10692 SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
    10693 SCIPconsGetName(cons), consdata->capacity, bestcapacity);
    10694
    10695 for( j = 0; j < nvars; ++j )
    10696 {
    10697 if( consdata->demands[j] == consdata->capacity )
    10698 {
    10699 consdata->demands[j] = bestcapacity;
    10700 (*nchgcoefs)++;
    10701 }
    10702 }
    10703
    10704 consdata->capacity = bestcapacity;
    10705 (*nchgsides)++;
    10706
    10707 SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
    10708
    10709 consdata->varbounds = FALSE;
    10710 }
    10711
    10712 return SCIP_OKAY;
    10713}
    10714
    10715
    10716/** tries to change coefficients:
    10717 * demand_j < cap && all other parallel jobs in conflict
    10718 * ==> set demand_j := cap
    10719 */
    10720static
    10722 SCIP* scip, /**< SCIP data structure */
    10723 SCIP_CONS* cons, /**< cumulative constraint */
    10724 int* nchgcoefs /**< pointer to count total number of changed coefficients */
    10725 )
    10726{
    10727 SCIP_CONSDATA* consdata;
    10728 int nvars;
    10729 int j;
    10730 int oldnchgcoefs;
    10731 int mindemand;
    10732
    10733 assert(scip != NULL);
    10734 assert(cons != NULL);
    10735 assert(nchgcoefs != NULL);
    10736
    10737 /* get constraint data for some parameter testings only! */
    10738 consdata = SCIPconsGetData(cons);
    10739 assert(consdata != NULL);
    10740
    10741 nvars = consdata->nvars;
    10742 oldnchgcoefs = *nchgcoefs;
    10743
    10744 if( nvars <= 0 )
    10745 return SCIP_OKAY;
    10746
    10747 /* PRE1:
    10748 * check all jobs j whether: r_j + r_min > capacity holds
    10749 * if so: adjust r_j to capacity
    10750 */
    10751 mindemand = consdata->demands[0];
    10752 for( j = 0; j < nvars; ++j )
    10753 {
    10754 mindemand = MIN(mindemand, consdata->demands[j]);
    10755 }
    10756
    10757 /*check each job */
    10758 for( j = 0; j < nvars; ++j )
    10759 {
    10760 if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
    10761 {
    10762 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
    10763 consdata->demands[j], consdata->capacity);
    10764 consdata->demands[j] = consdata->capacity;
    10765 (*nchgcoefs)++;
    10766 }
    10767 }
    10768
    10769 /* PRE2:
    10770 * check for each job (with d_j < cap)
    10771 * whether it is disjunctive to all others over the time horizon
    10772 */
    10773 for( j = 0; j < nvars; ++j )
    10774 {
    10775 SCIP_Bool chgcoef;
    10776 int est_j;
    10777 int lct_j;
    10778 int i;
    10779
    10780 assert(consdata->demands[j] <= consdata->capacity);
    10781
    10782 if( consdata->demands[j] == consdata->capacity )
    10783 continue;
    10784
    10785 chgcoef = TRUE;
    10786
    10787 est_j = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
    10788 lct_j = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
    10789
    10790 for( i = 0; i < nvars; ++i )
    10791 {
    10792 int est_i;
    10793 int lct_i;
    10794
    10795 if( i == j )
    10796 continue;
    10797
    10798 est_i = boundedConvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
    10799 lct_i = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
    10800
    10801 if( est_i >= lct_j || est_j >= lct_i )
    10802 continue;
    10803
    10804 if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
    10805 {
    10806 chgcoef = FALSE;
    10807 break;
    10808 }
    10809 }
    10810
    10811 if( chgcoef )
    10812 {
    10813 SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
    10814 consdata->demands[j], consdata->capacity);
    10815 consdata->demands[j] = consdata->capacity;
    10816 (*nchgcoefs)++;
    10817 }
    10818 }
    10819
    10820 if( (*nchgcoefs) > oldnchgcoefs )
    10821 {
    10822 SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
    10823 (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
    10824 }
    10825
    10826 return SCIP_OKAY;
    10827}
    10828
    10829#ifdef SCIP_DISABLED_CODE
    10830/* The following should work, but does not seem to be tested well. */
    10831
    10832/** try to reformulate constraint by replacing certain jobs */
    10833static
    10834SCIP_RETCODE reformulateCons(
    10835 SCIP* scip, /**< SCIP data structure */
    10836 SCIP_CONS* cons, /**< cumulative constraint */
    10837 int* naggrvars /**< pointer to store the number of aggregated variables */
    10838 )
    10839{
    10840 SCIP_CONSDATA* consdata;
    10841 int hmin;
    10842 int hmax;
    10843 int nvars;
    10844 int v;
    10845
    10846 consdata = SCIPconsGetData(cons);
    10847 assert(cons != NULL);
    10848
    10849 nvars = consdata->nvars;
    10850 assert(nvars > 1);
    10851
    10852 hmin = consdata->hmin;
    10853 hmax = consdata->hmax;
    10854 assert(hmin < hmax);
    10855
    10856 for( v = 0; v < nvars; ++v )
    10857 {
    10858 SCIP_VAR* var;
    10859 int duration;
    10860 int est;
    10861 int ect;
    10862 int lst;
    10863 int lct;
    10864
    10865 var = consdata->vars[v];
    10866 assert(var != NULL);
    10867
    10868 duration = consdata->durations[v];
    10869
    10871 ect = est + duration;
    10873 lct = lst + duration;
    10874
    10875 /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
    10876 assert(lst > hmin || ect < hmax);
    10877
    10878 if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
    10879 {
    10880 SCIP_VAR* aggrvar;
    10881 char name[SCIP_MAXSTRLEN];
    10882 SCIP_Bool infeasible;
    10883 SCIP_Bool redundant;
    10884 SCIP_Bool aggregated;
    10885 int shift;
    10886
    10887 shift = est - (hmin - lct + MIN(hmin, ect));
    10888 assert(shift > 0);
    10889 lst = hmin;
    10890 duration = hmin - lct;
    10891
    10892 SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
    10893 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
    10894
    10895 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
    10896 SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
    10898 SCIP_CALL( SCIPaddVar(scip, var) );
    10899 SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
    10900
    10901 assert(!infeasible);
    10902 assert(!redundant);
    10903 assert(aggregated);
    10904
    10905 /* replace variable */
    10906 consdata->durations[v] = duration;
    10907 consdata->vars[v] = aggrvar;
    10908
    10909 /* remove and add locks */
    10910 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
    10911 SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
    10912
    10913 SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
    10914
    10915 (*naggrvars)++;
    10916 }
    10917 }
    10918
    10919 return SCIP_OKAY;
    10920}
    10921#endif
    10922
    10923/** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
    10924static
    10926 SCIP* scip, /**< SCIP data structure */
    10927 SCIP_CONS* cons, /**< cumulative constraint */
    10928 int* naddconss /**< pointer to store the number of added constraints */
    10929 )
    10930{
    10931 SCIP_CONSDATA* consdata;
    10932 SCIP_VAR** vars;
    10933 int* durations;
    10934 int* demands;
    10935 int capacity;
    10936 int halfcapacity;
    10937 int mindemand;
    10938 int nvars;
    10939 int v;
    10940
    10941 consdata = SCIPconsGetData(cons);
    10942 assert(consdata != NULL);
    10943
    10944 capacity = consdata->capacity;
    10945
    10946 if( capacity == 1 )
    10947 return SCIP_OKAY;
    10948
    10949 SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
    10950 SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
    10951 SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
    10952
    10953 halfcapacity = capacity / 2;
    10954 mindemand = consdata->capacity;
    10955 nvars = 0;
    10956
    10957 /* collect all jobs with demand larger than half of the capacity */
    10958 for( v = 0; v < consdata->nvars; ++v )
    10959 {
    10960 if( consdata->demands[v] > halfcapacity )
    10961 {
    10962 vars[nvars] = consdata->vars[v];
    10963 demands[nvars] = 1;
    10964 durations[nvars] = consdata->durations[v];
    10965 nvars++;
    10966
    10967 mindemand = MIN(mindemand, consdata->demands[v]);
    10968 }
    10969 }
    10970
    10971 if( nvars > 0 )
    10972 {
    10973 /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
    10974 * job is still to large to be scheduled in parallel
    10975 */
    10976 for( v = 0; v < consdata->nvars; ++v )
    10977 {
    10978 if( consdata->demands[v] > halfcapacity )
    10979 continue;
    10980
    10981 if( mindemand + consdata->demands[v] > capacity )
    10982 {
    10983 demands[nvars] = 1;
    10984 durations[nvars] = consdata->durations[v];
    10985 vars[nvars] = consdata->vars[v];
    10986 nvars++;
    10987
    10988 /* @todo create one cumulative constraint and look for another small demand */
    10989 break;
    10990 }
    10991 }
    10992
    10993 /* creates cumulative constraint and adds it to problem */
    10994 SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
    10996 (*naddconss)++;
    10997 }
    10998
    10999 SCIPfreeBufferArray(scip, &demands);
    11000 SCIPfreeBufferArray(scip, &durations);
    11001 SCIPfreeBufferArray(scip, &vars);
    11002
    11003 return SCIP_OKAY;
    11004}
    11005
    11006/** presolve given constraint */
    11007static
    11009 SCIP* scip, /**< SCIP data structure */
    11010 SCIP_CONS* cons, /**< cumulative constraint */
    11011 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    11012 SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
    11013 int* nfixedvars, /**< pointer to store the number of fixed variables */
    11014 int* nchgbds, /**< pointer to store the number of changed bounds */
    11015 int* ndelconss, /**< pointer to store the number of deleted constraints */
    11016 int* naddconss, /**< pointer to store the number of added constraints */
    11017 int* nchgcoefs, /**< pointer to store the number of changed coefficients */
    11018 int* nchgsides, /**< pointer to store the number of changed sides */
    11019 SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
    11020 SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
    11021 )
    11022{
    11023 assert(!SCIPconsIsDeleted(cons));
    11024
    11025 /* only perform dual reductions on model constraints */
    11026 if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
    11027 {
    11028 /* computes the effective horizon and checks if the constraint can be decomposed */
    11029 SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
    11030
    11031 if( SCIPconsIsDeleted(cons) )
    11032 return SCIP_OKAY;
    11033
    11034 /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
    11035 * fixings (dual reductions)
    11036 */
    11037 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    11038 {
    11039 SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
    11040
    11041 if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
    11042 return SCIP_OKAY;
    11043 }
    11044
    11045 SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
    11046
    11047 if( *cutoff || SCIPconsIsDeleted(cons) )
    11048 return SCIP_OKAY;
    11049 }
    11050
    11051 /* remove jobs which have a demand larger than the capacity */
    11052 SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
    11053 assert((*cutoff) || checkDemands(scip, cons));
    11054
    11055 if( *cutoff )
    11056 return SCIP_OKAY;
    11057
    11058 if( conshdlrdata->normalize )
    11059 {
    11060 /* divide demands by their greatest common divisor */
    11061 normalizeDemands(scip, cons, nchgcoefs, nchgsides);
    11062 }
    11063
    11064 /* delete constraint with one job */
    11065 SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
    11066
    11067 if( *cutoff || SCIPconsIsDeleted(cons) )
    11068 return SCIP_OKAY;
    11069
    11070 if( conshdlrdata->coeftightening )
    11071 {
    11072 /* try to tighten the capacity */
    11073 SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
    11074
    11075 /* try to tighten the coefficients */
    11076 SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
    11077 }
    11078
    11079 assert(checkDemands(scip, cons) || *cutoff);
    11080
    11081#ifdef SCIP_DISABLED_CODE
    11082 /* The following should work, but does not seem to be tested well. */
    11083 SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
    11084#endif
    11085
    11086 return SCIP_OKAY;
    11087}
    11088
    11089/**@name TClique Graph callbacks
    11090 *
    11091 * @{
    11092 */
    11093
    11094/** tclique graph data */
    11095struct TCLIQUE_Graph
    11096{
    11097 SCIP_VAR** vars; /**< start time variables each of them is a node */
    11098 SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
    11099 SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
    11100 SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
    11101 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
    11102 int* ninarcs; /**< number if in arcs for the precedence graph */
    11103 int* noutarcs; /**< number if out arcs for the precedence graph */
    11104 int* durations; /**< for each node the duration of the corresponding job */
    11105 int nnodes; /**< number of nodes */
    11106 int size; /**< size of the array */
    11107};
    11108
    11109/** gets number of nodes in the graph */
    11110static
    11111TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
    11112{
    11113 assert(tcliquegraph != NULL);
    11114
    11115 return tcliquegraph->nnodes;
    11116}
    11117
    11118/** gets weight of nodes in the graph */
    11119static
    11120TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
    11121{
    11122 assert(tcliquegraph != NULL);
    11123
    11124 return tcliquegraph->weights;
    11125}
    11126
    11127/** returns, whether the edge (node1, node2) is in the graph */
    11128static
    11129TCLIQUE_ISEDGE(tcliqueIsedgeClique)
    11130{
    11131 assert(tcliquegraph != NULL);
    11132 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
    11133 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
    11134
    11135 /* check if an arc exits in the precedence graph */
    11136 if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
    11137 return TRUE;
    11138
    11139 /* check if an edge exits in the non-overlapping graph */
    11140 if( tcliquegraph->demandmatrix[node1][node2] )
    11141 return TRUE;
    11142
    11143 return FALSE;
    11144}
    11145
    11146/** selects all nodes from a given set of nodes which are adjacent to a given node
    11147 * and returns the number of selected nodes
    11148 */
    11149static
    11150TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
    11151{
    11152 int nadjnodes;
    11153 int i;
    11154
    11155 assert(tcliquegraph != NULL);
    11156 assert(0 <= node && node < tcliquegraph->nnodes);
    11157 assert(nnodes == 0 || nodes != NULL);
    11158 assert(adjnodes != NULL);
    11159
    11160 nadjnodes = 0;
    11161
    11162 for( i = 0; i < nnodes; i++ )
    11163 {
    11164 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
    11165 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
    11166 assert(i == 0 || nodes[i-1] < nodes[i]);
    11167
    11168 /* check if an edge exists */
    11169 if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
    11170 {
    11171 /* current node is adjacent to given node */
    11172 adjnodes[nadjnodes] = nodes[i];
    11173 nadjnodes++;
    11174 }
    11175 }
    11176
    11177 return nadjnodes;
    11178}
    11179
    11180/** generates cuts using a clique found by algorithm for maximum weight clique
    11181 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
    11182 */
    11183static
    11184TCLIQUE_NEWSOL(tcliqueNewsolClique)
    11185{ /*lint --e{715}*/
    11186 SCIPdebugMessage("####### max clique %d\n", cliqueweight);
    11187}
    11188
    11189
    11190/** @} */
    11191
    11192/** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
    11193 * job corresponding to variable bound variable (vlbvar)
    11194 *
    11195 * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
    11196 */
    11197static
    11199 SCIP* scip, /**< SCIP data structure */
    11200 SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
    11201 SCIP_Real vlbcoef, /**< variable bound coefficient */
    11202 SCIP_Real vlbconst, /**< variable bound constant */
    11203 int duration /**< duration of the variable bound variable */
    11204 )
    11205{
    11206 if( SCIPisEQ(scip, vlbcoef, 1.0) )
    11207 {
    11208 if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
    11209 {
    11210 /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
    11211 return TRUE;
    11212 }
    11213 }
    11214 else
    11215 {
    11217
    11218 bound = (duration - vlbcoef) / (vlbcoef - 1.0);
    11219
    11220 if( SCIPisLT(scip, vlbcoef, 1.0) )
    11221 {
    11222 SCIP_Real ub;
    11223
    11224 ub = SCIPvarGetUbLocal(vlbvar);
    11225
    11226 /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
    11227 if( SCIPisLE(scip, ub, bound) )
    11228 return TRUE;
    11229 }
    11230 else
    11231 {
    11232 SCIP_Real lb;
    11233
    11234 assert(SCIPisGT(scip, vlbcoef, 1.0));
    11235
    11236 lb = SCIPvarGetLbLocal(vlbvar);
    11237
    11238 /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
    11239 if( SCIPisGE(scip, lb, bound) )
    11240 return TRUE;
    11241 }
    11242 }
    11243
    11244 return FALSE;
    11245}
    11246
    11247/** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
    11248 * job corresponding to variable which is bounded (var)
    11249 *
    11250 * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
    11251 */
    11252static
    11254 SCIP* scip, /**< SCIP data structure */
    11255 SCIP_VAR* var, /**< variable which is bound from above */
    11256 SCIP_Real vubcoef, /**< variable bound coefficient */
    11257 SCIP_Real vubconst, /**< variable bound constant */
    11258 int duration /**< duration of the variable which is bounded from above */
    11259 )
    11260{
    11261 SCIP_Real vlbcoef;
    11262 SCIP_Real vlbconst;
    11263
    11264 /* convert the variable upper bound into an variable lower bound */
    11265 vlbcoef = 1.0 / vubcoef;
    11266 vlbconst = -vubconst / vubcoef;
    11267
    11268 return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
    11269}
    11270
    11271/** get the corresponding index of the given variables; this in case of an active variable the problem index and for
    11272 * others an index larger than the number if active variables
    11273 */
    11274static
    11276 SCIP* scip, /**< SCIP data structure */
    11277 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
    11278 SCIP_VAR* var, /**< variable for which we want the index */
    11279 int* idx /**< pointer to store the index */
    11280 )
    11281{
    11282 (*idx) = SCIPvarGetProbindex(var);
    11283
    11284 if( (*idx) == -1 )
    11285 {
    11286 if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
    11287 {
    11288 (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
    11289 }
    11290 else
    11291 {
    11292 int pos;
    11293 int v;
    11294
    11295 /**@todo we might want to add the aggregation path to graph */
    11296
    11297 /* check if we have to realloc memory */
    11298 if( tcliquegraph->size == tcliquegraph->nnodes )
    11299 {
    11300 int size;
    11301
    11302 size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
    11303 tcliquegraph->size = size;
    11304
    11305 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
    11306 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
    11307 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
    11308 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
    11309 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
    11310
    11311 for( v = 0; v < tcliquegraph->nnodes; ++v )
    11312 {
    11313 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
    11314 SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
    11315 }
    11316 }
    11317 assert(tcliquegraph->nnodes < tcliquegraph->size);
    11318
    11319 pos = tcliquegraph->nnodes;
    11320 assert(pos >= 0);
    11321
    11322 tcliquegraph->durations[pos] = 0;
    11323 tcliquegraph->weights[pos] = 0;
    11324 tcliquegraph->vars[pos] = var;
    11325
    11326 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
    11327 BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
    11328
    11329 SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
    11330 BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
    11331
    11332 SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
    11333
    11334 tcliquegraph->nnodes++;
    11335
    11336 for( v = 0; v < tcliquegraph->nnodes; ++v )
    11337 {
    11338 tcliquegraph->precedencematrix[v][pos] = 0;
    11339 tcliquegraph->demandmatrix[v][pos] = 0;
    11340 }
    11341
    11342 (*idx) = tcliquegraph->nnodes;
    11343 }
    11344 }
    11345 else
    11346 {
    11347 assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
    11348 }
    11349
    11350 assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
    11351
    11352 return SCIP_OKAY;
    11353}
    11354
    11355/** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
    11356 *
    11357 * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
    11358 * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
    11359 *
    11360 * (i) b = 1 and c >= d
    11361 * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
    11362 * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
    11363 *
    11364 */
    11365static
    11367 SCIP* scip, /**< SCIP data structure */
    11368 TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
    11369 )
    11370{
    11371 SCIP_VAR** vars;
    11372 int nvars;
    11373 int v;
    11374
    11375 vars = SCIPgetVars(scip);
    11376 nvars = SCIPgetNVars(scip);
    11377
    11378 /* try to project each arc of the variable bound graph to precedence condition */
    11379 for( v = 0; v < nvars; ++v )
    11380 {
    11381 SCIP_VAR** vbdvars;
    11382 SCIP_VAR* var;
    11383 SCIP_Real* vbdcoefs;
    11384 SCIP_Real* vbdconsts;
    11385 int nvbdvars;
    11386 int idx1;
    11387 int b;
    11388
    11389 var = vars[v];
    11390 assert(var != NULL);
    11391
    11392 SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
    11393 assert(idx1 >= 0);
    11394
    11395 if( tcliquegraph->durations[idx1] == 0 )
    11396 continue;
    11397
    11398 vbdvars = SCIPvarGetVlbVars(var);
    11399 vbdcoefs = SCIPvarGetVlbCoefs(var);
    11400 vbdconsts = SCIPvarGetVlbConstants(var);
    11401 nvbdvars = SCIPvarGetNVlbs(var);
    11402
    11403 for( b = 0; b < nvbdvars; ++b )
    11404 {
    11405 int idx2;
    11406
    11407 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
    11408 assert(idx2 >= 0);
    11409
    11410 if( tcliquegraph->durations[idx2] == 0 )
    11411 continue;
    11412
    11413 if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
    11414 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
    11415 }
    11416
    11417 vbdvars = SCIPvarGetVubVars(var);
    11418 vbdcoefs = SCIPvarGetVubCoefs(var);
    11419 vbdconsts = SCIPvarGetVubConstants(var);
    11420 nvbdvars = SCIPvarGetNVubs(var);
    11421
    11422 for( b = 0; b < nvbdvars; ++b )
    11423 {
    11424 int idx2;
    11425
    11426 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
    11427 assert(idx2 >= 0);
    11428
    11429 if( tcliquegraph->durations[idx2] == 0 )
    11430 continue;
    11431
    11432 if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
    11433 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
    11434 }
    11435
    11436 for( b = v+1; b < nvars; ++b )
    11437 {
    11438 int idx2;
    11439
    11440 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
    11441 assert(idx2 >= 0);
    11442
    11443 if( tcliquegraph->durations[idx2] == 0 )
    11444 continue;
    11445
    11446 /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
    11447 if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
    11448 tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
    11449
    11450 /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
    11451 if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
    11452 tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
    11453 }
    11454 }
    11455
    11456 return SCIP_OKAY;
    11457}
    11458
    11459/** compute the transitive closer of the given graph and the number of in and out arcs */
    11460static
    11462 SCIP_Bool** adjmatrix, /**< adjacent matrix */
    11463 int* ninarcs, /**< array to store the number of in arcs */
    11464 int* noutarcs, /**< array to store the number of out arcs */
    11465 int nnodes /**< number if nodes */
    11466 )
    11467{
    11468 int i;
    11469 int j;
    11470 int k;
    11471
    11472 for( i = 0; i < nnodes; ++i )
    11473 {
    11474 for( j = 0; j < nnodes; ++j )
    11475 {
    11476 if( adjmatrix[i][j] )
    11477 {
    11478 ninarcs[j]++;
    11479 noutarcs[i]++;
    11480
    11481 for( k = 0; k < nnodes; ++k )
    11482 {
    11483 if( adjmatrix[j][k] )
    11484 adjmatrix[i][k] = TRUE;
    11485 }
    11486 }
    11487 }
    11488 }
    11489}
    11490
    11491/** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
    11492static
    11494 SCIP* scip, /**< SCIP data structure */
    11495 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
    11496 SCIP_CONS** conss, /**< array of cumulative constraints */
    11497 int nconss /**< number of cumulative constraints */
    11498 )
    11499{
    11500 int c;
    11501
    11502 /* use the cumulative constraints to initialize the none overlapping graph */
    11503 for( c = 0; c < nconss; ++c )
    11504 {
    11505 SCIP_CONSDATA* consdata;
    11506 SCIP_VAR** vars;
    11507 int* demands;
    11508 int capacity;
    11509 int nvars;
    11510 int i;
    11511
    11512 consdata = SCIPconsGetData(conss[c]);
    11513 assert(consdata != NULL);
    11514
    11515 vars = consdata->vars;
    11516 demands = consdata->demands;
    11517
    11518 nvars = consdata->nvars;
    11519 capacity = consdata->capacity;
    11520
    11521 SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
    11522
    11523 /* check pairwise if two jobs have a cumulative demand larger than the capacity */
    11524 for( i = 0; i < nvars; ++i )
    11525 {
    11526 int idx1;
    11527 int j;
    11528
    11529 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
    11530 assert(idx1 >= 0);
    11531
    11532 if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
    11533 continue;
    11534
    11535 for( j = i+1; j < nvars; ++j )
    11536 {
    11537 assert(consdata->durations[j] > 0);
    11538
    11539 if( demands[i] + demands[j] > capacity )
    11540 {
    11541 int idx2;
    11542 int est1;
    11543 int est2;
    11544 int lct1;
    11545 int lct2;
    11546
    11547 /* check if the effective horizon is large enough */
    11550
    11551 /* at least one of the jobs needs to start at hmin or later */
    11552 if( est1 < consdata->hmin && est2 < consdata->hmin )
    11553 continue;
    11554
    11555 lct1 = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
    11556 lct2 = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
    11557
    11558 /* at least one of the jobs needs to finish not later then hmin */
    11559 if( lct1 > consdata->hmax && lct2 > consdata->hmax )
    11560 continue;
    11561
    11562 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
    11563 assert(idx2 >= 0);
    11564 assert(idx1 != idx2);
    11565
    11566 if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
    11567 continue;
    11568
    11569 SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
    11570
    11571 assert(tcliquegraph->durations[idx1] > 0);
    11572 assert(tcliquegraph->durations[idx2] > 0);
    11573
    11574 tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
    11575 tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
    11576 }
    11577 }
    11578 }
    11579 }
    11580
    11581 return SCIP_OKAY;
    11582}
    11583
    11584/** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
    11585 * of jobs cannot run in parallel
    11586 */
    11587static
    11589 SCIP* scip, /**< SCIP data structure */
    11590 TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
    11591 SCIP_CONS** conss, /**< array of cumulative constraints */
    11592 int nconss /**< number of cumulative constraints */
    11593 )
    11594{
    11595 assert(scip != NULL);
    11596 assert(tcliquegraph != NULL);
    11597
    11598 /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
    11599 SCIP_CALL( projectVbd(scip, tcliquegraph) );
    11600
    11601 /* compute the transitive closure of the precedence graph and the number of in and out arcs */
    11602 transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
    11603
    11604 /* constraints non-overlapping graph */
    11605 SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
    11606
    11607 return SCIP_OKAY;
    11608}
    11609
    11610/** create cumulative constraint from conflict set */
    11611static
    11613 SCIP* scip, /**< SCIP data structure */
    11614 const char* name, /**< constraint name */
    11615 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
    11616 int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
    11617 int ncliquenodes /**< number of nodes in the clique */
    11618 )
    11619{
    11620 SCIP_CONS* cons;
    11621 SCIP_VAR** vars;
    11622 int* durations;
    11623 int* demands;
    11624 int v;
    11625
    11626 SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
    11627 SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
    11628 SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
    11629
    11630 SCIPsortInt(cliquenodes, ncliquenodes);
    11631
    11632 /* collect variables, durations, and demands */
    11633 for( v = 0; v < ncliquenodes; ++v )
    11634 {
    11635 durations[v] = tcliquegraph->durations[cliquenodes[v]];
    11636 assert(durations[v] > 0);
    11637 demands[v] = 1;
    11638 vars[v] = tcliquegraph->vars[cliquenodes[v]];
    11639 }
    11640
    11641 /* create (unary) cumulative constraint */
    11642 SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
    11644
    11645 SCIP_CALL( SCIPaddCons(scip, cons) );
    11646 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    11647
    11648 /* free buffers */
    11649 SCIPfreeBufferArray(scip, &demands);
    11650 SCIPfreeBufferArray(scip, &durations);
    11651 SCIPfreeBufferArray(scip, &vars);
    11652
    11653 return SCIP_OKAY;
    11654}
    11655
    11656/** search for cumulative constrainst */
    11657static
    11659 SCIP* scip, /**< SCIP data structure */
    11660 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
    11661 int* naddconss /**< pointer to store the number of added constraints */
    11662 )
    11663{
    11664 TCLIQUE_STATUS tcliquestatus;
    11665 SCIP_Bool* precedencerow;
    11666 SCIP_Bool* precedencecol;
    11667 SCIP_Bool* demandrow;
    11668 SCIP_Bool* demandcol;
    11669 SCIP_HASHTABLE* covered;
    11670 int* cliquenodes;
    11671 int ncliquenodes;
    11672 int cliqueweight;
    11673 int ntreenodes;
    11674 int nnodes;
    11675 int nconss;
    11676 int v;
    11677
    11678 nnodes = tcliquegraph->nnodes;
    11679 nconss = 0;
    11680
    11681 /* initialize the weight of each job with its duration */
    11682 for( v = 0; v < nnodes; ++v )
    11683 {
    11684 tcliquegraph->weights[v] = tcliquegraph->durations[v];
    11685 }
    11686
    11687 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
    11688 SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
    11689 SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
    11690 SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
    11691 SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
    11692
    11693 /* create a hash table to store all start time variables which are already covered by at least one clique */
    11695 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
    11696
    11697 /* for each variables/job we are ... */
    11698 for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
    11699 {
    11700 char name[SCIP_MAXSTRLEN];
    11701 int c;
    11702
    11703 /* jobs with zero durations are skipped */
    11704 if( tcliquegraph->durations[v] == 0 )
    11705 continue;
    11706
    11707 /* check if the start time variable is already covered by at least one clique */
    11708 if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
    11709 continue;
    11710
    11711 SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
    11712
    11713 /* temporarily remove the connection via the precedence graph */
    11714 for( c = 0; c < nnodes; ++c )
    11715 {
    11716 precedencerow[c] = tcliquegraph->precedencematrix[v][c];
    11717 precedencecol[c] = tcliquegraph->precedencematrix[c][v];
    11718
    11719 demandrow[c] = tcliquegraph->demandmatrix[v][c];
    11720 demandcol[c] = tcliquegraph->demandmatrix[c][v];
    11721
    11722 tcliquegraph->precedencematrix[c][v] = FALSE;
    11723 tcliquegraph->precedencematrix[v][c] = FALSE;
    11724 }
    11725
    11726 /* find (heuristically) maximum cliques which includes node v */
    11727 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
    11728 tcliquegraph, tcliqueNewsolClique, NULL,
    11729 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
    11730 10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
    11731
    11732 SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
    11733
    11734 if( ncliquenodes == 1 )
    11735 continue;
    11736
    11737 /* construct constraint name */
    11738 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
    11739
    11740 SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
    11741 nconss++;
    11742
    11743 /* all start time variable to covered hash table */
    11744 for( c = 0; c < ncliquenodes; ++c )
    11745 {
    11746 SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
    11747 }
    11748
    11749 /* copy the precedence relations back */
    11750 for( c = 0; c < nnodes; ++c )
    11751 {
    11752 tcliquegraph->precedencematrix[v][c] = precedencerow[c];
    11753 tcliquegraph->precedencematrix[c][v] = precedencecol[c];
    11754
    11755 tcliquegraph->demandmatrix[v][c] = demandrow[c];
    11756 tcliquegraph->demandmatrix[c][v] = demandcol[c];
    11757 }
    11758 }
    11759
    11760 SCIPhashtableFree(&covered);
    11761
    11762 SCIPfreeBufferArray(scip, &demandcol);
    11763 SCIPfreeBufferArray(scip, &demandrow);
    11764 SCIPfreeBufferArray(scip, &precedencecol);
    11765 SCIPfreeBufferArray(scip, &precedencerow);
    11766 SCIPfreeBufferArray(scip, &cliquenodes);
    11767
    11768 (*naddconss) += nconss;
    11769
    11770 /* for the statistic we count the number added disjunctive constraints */
    11771 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
    11772
    11773 return SCIP_OKAY;
    11774}
    11775
    11776/** create precedence constraint (as variable bound constraint */
    11777static
    11779 SCIP* scip, /**< SCIP data structure */
    11780 const char* name, /**< constraint name */
    11781 SCIP_VAR* var, /**< variable x that has variable bound */
    11782 SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
    11783 int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
    11784 )
    11785{
    11786 SCIP_CONS* cons;
    11787
    11788 /* create variable bound constraint */
    11789 SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
    11791
    11793
    11794 /* add constraint to problem and release it */
    11795 SCIP_CALL( SCIPaddCons(scip, cons) );
    11796 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    11797
    11798 return SCIP_OKAY;
    11799}
    11800
    11801/** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
    11802static
    11804 SCIP* scip, /**< SCIP data structure */
    11805 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
    11806 int source, /**< index of the source node */
    11807 int sink, /**< index of the sink node */
    11808 int* naddconss /**< pointer to store the number of added constraints */
    11809 )
    11810{
    11811 TCLIQUE_WEIGHT cliqueweight;
    11812 TCLIQUE_STATUS tcliquestatus;
    11813 SCIP_VAR** vars;
    11814 int* cliquenodes;
    11815 int nnodes;
    11816 int lct;
    11817 int est;
    11818 int i;
    11819
    11820 int ntreenodes;
    11821 int ncliquenodes;
    11822
    11823 /* check if source and sink are connencted */
    11824 if( !tcliquegraph->precedencematrix[source][sink] )
    11825 return SCIP_OKAY;
    11826
    11827 nnodes = tcliquegraph->nnodes;
    11828 vars = tcliquegraph->vars;
    11829
    11830 /* reset the weights to zero */
    11831 BMSclearMemoryArray(tcliquegraph->weights, nnodes);
    11832
    11833 /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
    11834 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
    11836
    11837 /* weight all jobs which run for sure between source and sink with their duration */
    11838 for( i = 0; i < nnodes; ++i )
    11839 {
    11840 SCIP_VAR* var;
    11841 int duration;
    11842
    11843 var = vars[i];
    11844 assert(var != NULL);
    11845
    11846 duration = tcliquegraph->durations[i];
    11847
    11848 if( i == source || i == sink )
    11849 {
    11850 /* source and sink are not weighted */
    11851 tcliquegraph->weights[i] = 0;
    11852 }
    11853 else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
    11854 {
    11855 /* job i runs after source and before sink */
    11856 tcliquegraph->weights[i] = duration;
    11857 }
    11858 else if( lct <= boundedConvertRealToInt(scip, SCIPvarGetLbLocal(var))
    11859 && est >= boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
    11860 {
    11861 /* job i run in between due the bounds of the start time variables */
    11862 tcliquegraph->weights[i] = duration;
    11863 }
    11864 else
    11865 tcliquegraph->weights[i] = 0;
    11866 }
    11867
    11868 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
    11869
    11870 /* find (heuristically) maximum cliques */
    11871 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
    11872 tcliquegraph, tcliqueNewsolClique, NULL,
    11873 cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
    11874 10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
    11875
    11876 if( ncliquenodes > 1 )
    11877 {
    11878 char name[SCIP_MAXSTRLEN];
    11879 int distance;
    11880
    11881 /* construct constraint name */
    11882 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
    11883
    11884 /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
    11885 * duration of the source job
    11886 */
    11887 distance = cliqueweight + tcliquegraph->durations[source];
    11888
    11889 SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
    11890 (*naddconss)++;
    11891 }
    11892
    11893 SCIPfreeBufferArray(scip, &cliquenodes);
    11894
    11895 return SCIP_OKAY;
    11896}
    11897
    11898/** search for precedence constraints
    11899 *
    11900 * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
    11901 * corresponding two jobs
    11902 */
    11903static
    11905 SCIP* scip, /**< SCIP data structure */
    11906 TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
    11907 int* naddconss /**< pointer to store the number of added constraints */
    11908 )
    11909{
    11910 int* sources;
    11911 int* sinks;
    11912 int nconss;
    11913 int nnodes;
    11914 int nsources;
    11915 int nsinks;
    11916 int i;
    11917
    11918 nnodes = tcliquegraph->nnodes;
    11919 nconss = 0;
    11920
    11921 nsources = 0;
    11922 nsinks = 0;
    11923
    11926
    11927 /* first collect all sources and sinks */
    11928 for( i = 0; i < nnodes; ++i )
    11929 {
    11930 if( tcliquegraph->ninarcs[i] == 0 )
    11931 {
    11932 sources[nsources] = i;
    11933 nsources++;
    11934 }
    11935
    11936 if( tcliquegraph->noutarcs[i] == 0 )
    11937 {
    11938 sinks[nsinks] = i;
    11939 nsinks++;
    11940 }
    11941 }
    11942
    11943 /* compute for each node a minimum distance to each sources and each sink */
    11944 for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
    11945 {
    11946 int j;
    11947
    11948 for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
    11949 {
    11950 SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
    11951 }
    11952
    11953 for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
    11954 {
    11955 SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
    11956 }
    11957 }
    11958
    11959 (*naddconss) += nconss;
    11960
    11961 /* for the statistic we count the number added variable constraints */
    11962 SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
    11963
    11964 SCIPfreeBufferArray(scip, &sinks);
    11965 SCIPfreeBufferArray(scip, &sources);
    11966
    11967 return SCIP_OKAY;
    11968}
    11969
    11970/** initialize the assumed durations for each variable */
    11971static
    11973 SCIP* scip, /**< SCIP data structure */
    11974 TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
    11975 SCIP_CONS** conss, /**< cumulative constraints */
    11976 int nconss /**< number of cumulative constraints */
    11977 )
    11978{
    11979 int c;
    11980
    11981 /* use the cumulative structure to define the duration we are using for each job */
    11982 for( c = 0; c < nconss; ++c )
    11983 {
    11984 SCIP_CONSDATA* consdata;
    11985 SCIP_VAR** vars;
    11986 int nvars;
    11987 int v;
    11988
    11989 consdata = SCIPconsGetData(conss[c]);
    11990 assert(consdata != NULL);
    11991
    11992 vars = consdata->vars;
    11993 nvars = consdata->nvars;
    11994
    11995 for( v = 0; v < nvars; ++v )
    11996 {
    11997 int idx;
    11998
    11999 SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
    12000 assert(idx >= 0);
    12001
    12002 /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
    12003 * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
    12004 * general this is not the case. Therefore, the question would be which duration should be used?
    12005 */
    12006 tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
    12007 assert(tcliquegraph->durations[idx] > 0);
    12008 }
    12009 }
    12010
    12011 return SCIP_OKAY;
    12012}
    12013
    12014/** create tclique graph */
    12015static
    12017 SCIP* scip, /**< SCIP data structure */
    12018 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
    12019 )
    12020{
    12021 SCIP_VAR** vars;
    12022 SCIP_HASHMAP* varmap;
    12023 SCIP_Bool** precedencematrix;
    12024 SCIP_Bool** demandmatrix;
    12025 int* ninarcs;
    12026 int* noutarcs;
    12027 int* durations;
    12028 int* weights;
    12029 int nvars;
    12030 int v;
    12031
    12032 vars = SCIPgetVars(scip);
    12033 nvars = SCIPgetNVars(scip);
    12034
    12035 /* allocate memory for the tclique graph data structure */
    12036 SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
    12037
    12038 /* create the variable mapping hash map */
    12039 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
    12040
    12041 /* each active variables get a node in the graph */
    12042 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
    12043
    12044 /* allocate memory for the projected variables bound graph and the none overlapping graph */
    12045 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
    12046 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
    12047
    12048 /* array to buffer the weights of the nodes for the maximum weighted clique computation */
    12049 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
    12050 BMSclearMemoryArray(weights, nvars);
    12051
    12052 /* array to store the number of in arc of the precedence graph */
    12053 SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
    12054 BMSclearMemoryArray(ninarcs, nvars);
    12055
    12056 /* array to store the number of out arc of the precedence graph */
    12057 SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
    12058 BMSclearMemoryArray(noutarcs, nvars);
    12059
    12060 /* array to store the used duration for each node */
    12061 SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
    12062 BMSclearMemoryArray(durations, nvars);
    12063
    12064 for( v = 0; v < nvars; ++v )
    12065 {
    12066 SCIP_VAR* var;
    12067
    12068 var = vars[v];
    12069 assert(var != NULL);
    12070
    12071 SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
    12072 BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
    12073
    12074 SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
    12075 BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
    12076
    12077 /* insert all active variables into the garph */
    12078 assert(SCIPvarGetProbindex(var) == v);
    12079 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
    12080 }
    12081
    12082 (*tcliquegraph)->nnodes = nvars;
    12083 (*tcliquegraph)->varmap = varmap;
    12084 (*tcliquegraph)->precedencematrix = precedencematrix;
    12085 (*tcliquegraph)->demandmatrix = demandmatrix;
    12086 (*tcliquegraph)->weights = weights;
    12087 (*tcliquegraph)->ninarcs = ninarcs;
    12088 (*tcliquegraph)->noutarcs = noutarcs;
    12089 (*tcliquegraph)->durations = durations;
    12090 (*tcliquegraph)->size = nvars;
    12091
    12092 return SCIP_OKAY;
    12093}
    12094
    12095/** frees the tclique graph */
    12096static
    12098 SCIP* scip, /**< SCIP data structure */
    12099 TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
    12100 )
    12101{
    12102 int v;
    12103
    12104 for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
    12105 {
    12106 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
    12107 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
    12108 }
    12109
    12110 SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
    12111 SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
    12112 SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
    12113 SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
    12114 SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
    12115 SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
    12116 SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
    12117 SCIPhashmapFree(&(*tcliquegraph)->varmap);
    12118
    12119 SCIPfreeBuffer(scip, tcliquegraph);
    12120}
    12121
    12122/** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
    12123 * constrains (disjunctive constraint)
    12124 */
    12125static
    12127 SCIP* scip, /**< SCIP data structure */
    12128 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
    12129 SCIP_CONS** conss, /**< array of cumulative constraints */
    12130 int nconss, /**< number of cumulative constraints */
    12131 int* naddconss /**< pointer to store the number of added constraints */
    12132 )
    12133{
    12134 TCLIQUE_GRAPH* tcliquegraph;
    12135
    12136 /* create tclique graph */
    12137 SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
    12138
    12139 /* define for each job a duration */
    12140 SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
    12141
    12142 /* constuct incompatibility graph */
    12143 SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
    12144
    12145 /* search for new precedence constraints */
    12146 if( conshdlrdata->detectvarbounds )
    12147 {
    12148 SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
    12149 }
    12150
    12151 /* search for new cumulative constraints */
    12152 if( conshdlrdata->detectdisjunctive )
    12153 {
    12154 SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
    12155 }
    12156
    12157 /* free tclique graph data structure */
    12158 freeTcliqueGraph(scip, &tcliquegraph);
    12159
    12160 return SCIP_OKAY;
    12161}
    12162
    12163/** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
    12164static
    12166 SCIP_CONSDATA* consdata /**< cumulative constraint data */
    12167 )
    12168{
    12169 SCIP_VAR** vars;
    12170 int nvars;
    12171 int v;
    12172
    12173 if( consdata->validsignature )
    12174 return;
    12175
    12176 vars = consdata->vars;
    12177 nvars = consdata->nvars;
    12178
    12179 for( v = 0; v < nvars; ++v )
    12180 {
    12181 consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
    12182 }
    12183
    12184 consdata->validsignature = TRUE;
    12185}
    12186
    12187/** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
    12188static
    12190{ /*lint --e{715}*/
    12191 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
    12192
    12193 assert(consdata != NULL);
    12194 assert(0 <= ind1 && ind1 < consdata->nvars);
    12195 assert(0 <= ind2 && ind2 < consdata->nvars);
    12196
    12197 return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
    12198}
    12199
    12200/** run a pairwise comparison */
    12201static
    12203 SCIP* scip, /**< SCIP data structure */
    12204 SCIP_CONS** conss, /**< array of cumulative constraints */
    12205 int nconss, /**< number of cumulative constraints */
    12206 int* ndelconss /**< pointer to store the number of deletedconstraints */
    12207 )
    12208{
    12209 int i;
    12210 int j;
    12211
    12212 for( i = 0; i < nconss; ++i )
    12213 {
    12214 SCIP_CONSDATA* consdata0;
    12215 SCIP_CONS* cons0;
    12216
    12217 cons0 = conss[i];
    12218 assert(cons0 != NULL);
    12219
    12220 consdata0 = SCIPconsGetData(cons0);
    12221 assert(consdata0 != NULL);
    12222
    12223 consdataCalcSignature(consdata0);
    12224 assert(consdata0->validsignature);
    12225
    12226 for( j = i+1; j < nconss; ++j )
    12227 {
    12228 SCIP_CONSDATA* consdata1;
    12229 SCIP_CONS* cons1;
    12230
    12231 cons1 = conss[j];
    12232 assert(cons1 != NULL);
    12233
    12234 consdata1 = SCIPconsGetData(cons1);
    12235 assert(consdata1 != NULL);
    12236
    12237 if( consdata0->capacity != consdata1->capacity )
    12238 continue;
    12239
    12240 consdataCalcSignature(consdata1);
    12241 assert(consdata1->validsignature);
    12242
    12243 if( (consdata1->signature & (~consdata0->signature)) == 0 )
    12244 {
    12245 SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
    12246 SCIPswapPointers((void**)&cons0, (void**)&cons1);
    12247 assert((consdata0->signature & (~consdata1->signature)) == 0);
    12248 }
    12249
    12250 if( (consdata0->signature & (~consdata1->signature)) == 0 )
    12251 {
    12252 int* perm0;
    12253 int* perm1;
    12254 int v0;
    12255 int v1;
    12256
    12257 if( consdata0->nvars > consdata1->nvars )
    12258 continue;
    12259
    12260 if( consdata0->hmin < consdata1->hmin )
    12261 continue;
    12262
    12263 if( consdata0->hmax > consdata1->hmax )
    12264 continue;
    12265
    12266 SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
    12267 SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
    12268
    12269 /* call sorting method */
    12270 SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
    12271 SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
    12272
    12273 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
    12274 {
    12275 SCIP_VAR* var0;
    12276 SCIP_VAR* var1;
    12277 int idx0;
    12278 int idx1;
    12279 int comp;
    12280
    12281 idx0 = perm0[v0];
    12282 idx1 = perm1[v1];
    12283
    12284 var0 = consdata0->vars[idx0];
    12285
    12286 var1 = consdata1->vars[idx1];
    12287
    12288 comp = SCIPvarCompare(var0, var1);
    12289
    12290 if( comp == 0 )
    12291 {
    12292 int duration0;
    12293 int duration1;
    12294 int demand0;
    12295 int demand1;
    12296
    12297 demand0 = consdata0->demands[idx0];
    12298 duration0 = consdata0->durations[idx0];
    12299
    12300 demand1 = consdata1->demands[idx1];
    12301 duration1 = consdata1->durations[idx1];
    12302
    12303 if( demand0 != demand1 )
    12304 break;
    12305
    12306 if( duration0 != duration1 )
    12307 break;
    12308
    12309 v0++;
    12310 v1++;
    12311 }
    12312 else if( comp > 0 )
    12313 v1++;
    12314 else
    12315 break;
    12316 }
    12317
    12318 if( v0 == consdata0->nvars )
    12319 {
    12320 if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
    12321 {
    12322 initializeLocks(consdata1, TRUE);
    12323 }
    12324
    12325 /* coverity[swapped_arguments] */
    12326 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
    12327
    12328 SCIP_CALL( SCIPdelCons(scip, cons0) );
    12329 (*ndelconss)++;
    12330 }
    12331
    12332 SCIPfreeBufferArray(scip, &perm1);
    12333 SCIPfreeBufferArray(scip, &perm0);
    12334 }
    12335 }
    12336 }
    12337
    12338 return SCIP_OKAY;
    12339}
    12340
    12341/** strengthen the variable bounds using the cumulative condition */
    12342static
    12344 SCIP* scip, /**< SCIP data structure */
    12345 SCIP_CONS* cons, /**< constraint to propagate */
    12346 int* nchgbds, /**< pointer to store the number of changed bounds */
    12347 int* naddconss /**< pointer to store the number of added constraints */
    12348 )
    12349{
    12350 SCIP_CONSDATA* consdata;
    12351 SCIP_VAR** vars;
    12352 int* durations;
    12353 int* demands;
    12354 int capacity;
    12355 int nvars;
    12356 int nconss;
    12357 int i;
    12358
    12359 consdata = SCIPconsGetData(cons);
    12360 assert(consdata != NULL);
    12361
    12362 /* check if the variable bounds got already strengthen by the cumulative constraint */
    12363 if( consdata->varbounds )
    12364 return SCIP_OKAY;
    12365
    12366 vars = consdata->vars;
    12367 durations = consdata->durations;
    12368 demands = consdata->demands;
    12369 capacity = consdata->capacity;
    12370 nvars = consdata->nvars;
    12371
    12372 nconss = 0;
    12373
    12374 for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
    12375 {
    12376 SCIP_VAR** vbdvars;
    12377 SCIP_VAR* var;
    12378 SCIP_Real* vbdcoefs;
    12379 SCIP_Real* vbdconsts;
    12380 int nvbdvars;
    12381 int b;
    12382 int j;
    12383
    12384 var = consdata->vars[i];
    12385 assert(var != NULL);
    12386
    12387 vbdvars = SCIPvarGetVlbVars(var);
    12388 vbdcoefs = SCIPvarGetVlbCoefs(var);
    12389 vbdconsts = SCIPvarGetVlbConstants(var);
    12390 nvbdvars = SCIPvarGetNVlbs(var);
    12391
    12392 for( b = 0; b < nvbdvars; ++b )
    12393 {
    12394 if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
    12395 {
    12396 if( boundedConvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
    12397 {
    12398 for( j = 0; j < nvars; ++j )
    12399 {
    12400 if( vars[j] == vbdvars[b] )
    12401 break;
    12402 }
    12403 if( j == nvars )
    12404 continue;
    12405
    12406 if( demands[i] + demands[j] > capacity &&
    12407 boundedConvertRealToInt(scip, vbdconsts[b]) < durations[j] )
    12408 {
    12409 SCIP_Bool infeasible;
    12410 char name[SCIP_MAXSTRLEN];
    12411 int nlocalbdchgs;
    12412
    12413 SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
    12414
    12415 /* construct constraint name */
    12416 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
    12417
    12418 SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
    12419 nconss++;
    12420
    12421 SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
    12422 assert(!infeasible);
    12423
    12424 (*nchgbds) += nlocalbdchgs;
    12425 }
    12426 }
    12427 }
    12428 }
    12429 }
    12430
    12431 (*naddconss) += nconss;
    12432
    12433 consdata->varbounds = TRUE;
    12434
    12435 return SCIP_OKAY;
    12436}
    12437
    12438/** helper function to enforce constraints */
    12439static
    12441 SCIP* scip, /**< SCIP data structure */
    12442 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    12443 SCIP_CONS** conss, /**< constraints to process */
    12444 int nconss, /**< number of constraints */
    12445 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
    12446 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    12447 SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
    12448 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    12449 )
    12450{
    12451 SCIP_CONSHDLRDATA* conshdlrdata;
    12452
    12453 assert(conshdlr != NULL);
    12454 assert(nconss == 0 || conss != NULL);
    12455 assert(result != NULL);
    12456
    12458
    12459 if( solinfeasible )
    12460 {
    12461 *result = SCIP_INFEASIBLE;
    12462 return SCIP_OKAY;
    12463 }
    12464
    12465 SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
    12466 sol == NULL ? "LP" : "relaxation");
    12467
    12468 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12469 assert(conshdlrdata != NULL);
    12470
    12471 (*result) = SCIP_FEASIBLE;
    12472
    12473 if( conshdlrdata->usebinvars )
    12474 {
    12475 SCIP_Bool separated;
    12476 SCIP_Bool cutoff;
    12477 int c;
    12478
    12479 separated = FALSE;
    12480
    12481 /* first check if a constraints is violated */
    12482 for( c = 0; c < nusefulconss; ++c )
    12483 {
    12484 SCIP_CONS* cons;
    12485 SCIP_Bool violated;
    12486
    12487 cons = conss[c];
    12488 assert(cons != NULL);
    12489
    12490 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
    12491
    12492 if( !violated )
    12493 continue;
    12494
    12495 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
    12496 if ( cutoff )
    12497 {
    12498 *result = SCIP_CUTOFF;
    12499 return SCIP_OKAY;
    12500 }
    12501 }
    12502
    12503 for( ; c < nconss && !separated; ++c )
    12504 {
    12505 SCIP_CONS* cons;
    12506 SCIP_Bool violated;
    12507
    12508 cons = conss[c];
    12509 assert(cons != NULL);
    12510
    12511 SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
    12512
    12513 if( !violated )
    12514 continue;
    12515
    12516 SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
    12517 if ( cutoff )
    12518 {
    12519 *result = SCIP_CUTOFF;
    12520 return SCIP_OKAY;
    12521 }
    12522 }
    12523
    12524 if( separated )
    12525 (*result) = SCIP_SEPARATED;
    12526 }
    12527 else
    12528 {
    12529 SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
    12530 }
    12531
    12532 return SCIP_OKAY;
    12533}
    12534
    12535/**@} */
    12536
    12537
    12538/**@name Callback methods of constraint handler
    12539 *
    12540 * @{
    12541 */
    12542
    12543/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    12544static
    12545SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
    12546{ /*lint --e{715}*/
    12547 assert(scip != NULL);
    12548 assert(conshdlr != NULL);
    12549
    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
    12571
    12572 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12573 assert(conshdlrdata != NULL);
    12574
    12575#ifdef SCIP_STATISTIC
    12576 if( !conshdlrdata->iscopy )
    12577 {
    12578 /* statisitc output if SCIP_STATISTIC is defined */
    12579 SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
    12580 conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
    12581 SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
    12582 conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
    12583 SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
    12584 conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
    12585 }
    12586#endif
    12587
    12588 conshdlrdataFree(scip, &conshdlrdata);
    12589
    12590 SCIPconshdlrSetData(conshdlr, NULL);
    12591
    12592 return SCIP_OKAY;
    12593}
    12594
    12595
    12596/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    12597static
    12598SCIP_DECL_CONSINITPRE(consInitpreCumulative)
    12599{ /*lint --e{715}*/
    12600 SCIP_CONSHDLRDATA* conshdlrdata;
    12601 int c;
    12602
    12603 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12604 assert(conshdlrdata != NULL);
    12605
    12606 conshdlrdata->detectedredundant = FALSE;
    12607
    12608 for( c = 0; c < nconss; ++c )
    12609 {
    12610 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
    12611 * hmax)
    12612 */
    12613 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
    12614 }
    12615
    12616 return SCIP_OKAY;
    12617}
    12618
    12619
    12620/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
    12621#ifdef SCIP_STATISTIC
    12622static
    12623SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
    12624{ /*lint --e{715}*/
    12625 SCIP_CONSHDLRDATA* conshdlrdata;
    12626 int c;
    12627
    12628 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12629 assert(conshdlrdata != NULL);
    12630
    12631 for( c = 0; c < nconss; ++c )
    12632 {
    12633 SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
    12634
    12635#ifdef SCIP_DISABLED_CODE
    12637#endif
    12638 }
    12639
    12640 if( !conshdlrdata->iscopy )
    12641 {
    12642 SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
    12643 SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
    12644 SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
    12645 SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
    12646 SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
    12647 SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
    12648 SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
    12649 SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
    12650 SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
    12651 }
    12652
    12653 return SCIP_OKAY;
    12654}
    12655#endif
    12656
    12657
    12658/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    12659static
    12660SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
    12661{ /*lint --e{715}*/
    12662 SCIP_CONSDATA* consdata;
    12663 int c;
    12664
    12665 assert(conshdlr != NULL);
    12666
    12668
    12669 /* release the rows of all constraints */
    12670 for( c = 0; c < nconss; ++c )
    12671 {
    12672 consdata = SCIPconsGetData(conss[c]);
    12673 assert(consdata != NULL);
    12674
    12675 /* free rows */
    12676 SCIP_CALL( consdataFreeRows(scip, &consdata) );
    12677 }
    12678
    12679 return SCIP_OKAY;
    12680}
    12681
    12682/** frees specific constraint data */
    12683static
    12684SCIP_DECL_CONSDELETE(consDeleteCumulative)
    12685{ /*lint --e{715}*/
    12686 assert(conshdlr != NULL);
    12687 assert(consdata != NULL );
    12688 assert(*consdata != NULL );
    12689
    12691
    12692 /* if constraint belongs to transformed problem space, drop bound change events on variables */
    12693 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
    12694 {
    12695 SCIP_CONSHDLRDATA* conshdlrdata;
    12696
    12697 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12698 assert(conshdlrdata != NULL);
    12699
    12700 SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
    12701 }
    12702
    12703 /* free cumulative constraint data */
    12704 SCIP_CALL( consdataFree(scip, consdata) );
    12705
    12706 return SCIP_OKAY;
    12707}
    12708
    12709/** transforms constraint data into data belonging to the transformed problem */
    12710static
    12711SCIP_DECL_CONSTRANS(consTransCumulative)
    12712{ /*lint --e{715}*/
    12713 SCIP_CONSHDLRDATA* conshdlrdata;
    12714 SCIP_CONSDATA* sourcedata;
    12715 SCIP_CONSDATA* targetdata;
    12716
    12717 assert(conshdlr != NULL);
    12719 assert(sourcecons != NULL);
    12720 assert(targetcons != NULL);
    12721
    12722 sourcedata = SCIPconsGetData(sourcecons);
    12723 assert(sourcedata != NULL);
    12724 assert(sourcedata->demandrows == NULL);
    12725
    12726 SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
    12727
    12728 /* get event handler */
    12729 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12730 assert(conshdlrdata != NULL);
    12731 assert(conshdlrdata->eventhdlr != NULL);
    12732
    12733 /* create constraint data for target constraint */
    12734 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
    12735 sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
    12736 sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
    12737
    12738 /* create target constraint */
    12739 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
    12740 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
    12741 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
    12742 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
    12743 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
    12744
    12745 /* catch bound change events of variables */
    12746 SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
    12747
    12748 return SCIP_OKAY;
    12749}
    12750
    12751/** LP initialization method of constraint handler */
    12752static
    12753SCIP_DECL_CONSINITLP(consInitlpCumulative)
    12754{
    12755 SCIP_CONSHDLRDATA* conshdlrdata;
    12756 int c;
    12757
    12758 assert(conshdlr != NULL);
    12759
    12761
    12762 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12763 assert(conshdlrdata != NULL);
    12764
    12765 *infeasible = FALSE;
    12766
    12767 SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
    12768
    12769 if( conshdlrdata->usebinvars )
    12770 {
    12771 /* add rows to LP */
    12772 for( c = 0; c < nconss && !(*infeasible); ++c )
    12773 {
    12774 assert(SCIPconsIsInitial(conss[c]));
    12775 SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
    12776
    12777 if( conshdlrdata->cutsasconss )
    12778 {
    12780 }
    12781 }
    12782 }
    12783
    12784 /**@todo if we want to use only the integer variables; only these will be in cuts
    12785 * create some initial cuts, currently these are only separated */
    12786
    12787 return SCIP_OKAY;
    12788}
    12789
    12790/** separation method of constraint handler for LP solutions */
    12791static
    12792SCIP_DECL_CONSSEPALP(consSepalpCumulative)
    12793{
    12794 SCIP_CONSHDLRDATA* conshdlrdata;
    12795 SCIP_Bool cutoff;
    12796 SCIP_Bool separated;
    12797 int c;
    12798
    12799 SCIPdebugMsg(scip, "consSepalpCumulative\n");
    12800
    12801 assert(conshdlr != NULL);
    12802 assert(nconss == 0 || conss != NULL);
    12803 assert(result != NULL);
    12804
    12806
    12807 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12808 assert(conshdlrdata != NULL);
    12809
    12810 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
    12811
    12812 cutoff = FALSE;
    12813 separated = FALSE;
    12814 (*result) = SCIP_DIDNOTRUN;
    12815
    12816 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
    12817 return SCIP_OKAY;
    12818
    12819 (*result) = SCIP_DIDNOTFIND;
    12820
    12821 if( conshdlrdata->usebinvars )
    12822 {
    12823 /* check all useful cumulative constraints for feasibility */
    12824 for( c = 0; c < nusefulconss && !cutoff; ++c )
    12825 {
    12826 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
    12827 }
    12828
    12829 if( !cutoff && conshdlrdata->usecovercuts )
    12830 {
    12831 for( c = 0; c < nusefulconss; ++c )
    12832 {
    12833 SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
    12834 }
    12835 }
    12836 }
    12837
    12838 if( conshdlrdata->sepaold )
    12839 {
    12840 /* separate cuts containing only integer variables */
    12841 for( c = 0; c < nusefulconss; ++c )
    12842 {
    12843 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
    12844 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
    12845 }
    12846 }
    12847
    12848 if( cutoff )
    12849 *result = SCIP_CUTOFF;
    12850 else if( separated )
    12851 *result = SCIP_SEPARATED;
    12852
    12853 return SCIP_OKAY;
    12854}
    12855
    12856/** separation method of constraint handler for arbitrary primal solutions */
    12857static
    12858SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
    12859{ /*lint --e{715}*/
    12860 SCIP_CONSHDLRDATA* conshdlrdata;
    12861 SCIP_Bool cutoff;
    12862 SCIP_Bool separated;
    12863 int c;
    12864
    12865 assert(conshdlr != NULL);
    12866 assert(nconss == 0 || conss != NULL);
    12867 assert(result != NULL);
    12868
    12870
    12871 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12872 assert(conshdlrdata != NULL);
    12873
    12874 if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
    12875 return SCIP_OKAY;
    12876
    12877 SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
    12878
    12879 cutoff = FALSE;
    12880 separated = FALSE;
    12881 (*result) = SCIP_DIDNOTFIND;
    12882
    12883 if( conshdlrdata->usebinvars )
    12884 {
    12885 /* check all useful cumulative constraints for feasibility */
    12886 for( c = 0; c < nusefulconss && !cutoff; ++c )
    12887 {
    12888 SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
    12889 }
    12890
    12891 if( !cutoff && conshdlrdata->usecovercuts )
    12892 {
    12893 for( c = 0; c < nusefulconss; ++c )
    12894 {
    12895 SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
    12896 }
    12897 }
    12898 }
    12899 if( conshdlrdata->sepaold )
    12900 {
    12901 /* separate cuts containing only integer variables */
    12902 for( c = 0; c < nusefulconss; ++c )
    12903 {
    12904 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
    12905 SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
    12906 }
    12907 }
    12908
    12909 if( cutoff )
    12910 *result = SCIP_CUTOFF;
    12911 else if( separated )
    12912 *result = SCIP_SEPARATED;
    12913
    12914 return SCIP_OKAY;
    12915}
    12916
    12917/** constraint enforcing method of constraint handler for LP solutions */
    12918static
    12919SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
    12920{ /*lint --e{715}*/
    12921 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
    12922
    12923 return SCIP_OKAY;
    12924}
    12925
    12926/** constraint enforcing method of constraint handler for relaxation solutions */
    12927static
    12928SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
    12929{ /*lint --e{715}*/
    12930 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
    12931
    12932 return SCIP_OKAY;
    12933}
    12934
    12935/** constraint enforcing method of constraint handler for pseudo solutions */
    12936static
    12937SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
    12938{ /*lint --e{715}*/
    12939 SCIP_CONSHDLRDATA* conshdlrdata;
    12940
    12941 SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
    12942
    12943 assert(conshdlr != NULL);
    12944 assert(nconss == 0 || conss != NULL);
    12945 assert(result != NULL);
    12946
    12948
    12949 if( objinfeasible )
    12950 {
    12951 *result = SCIP_DIDNOTRUN;
    12952 return SCIP_OKAY;
    12953 }
    12954
    12955 (*result) = SCIP_FEASIBLE;
    12956
    12957 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12958 assert(conshdlrdata != NULL);
    12959
    12960 SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
    12961
    12962 return SCIP_OKAY;
    12963}
    12964
    12965/** feasibility check method of constraint handler for integral solutions */
    12966static
    12967SCIP_DECL_CONSCHECK(consCheckCumulative)
    12968{ /*lint --e{715}*/
    12969 int c;
    12970
    12971 assert(conshdlr != NULL);
    12972 assert(nconss == 0 || conss != NULL);
    12973 assert(result != NULL);
    12974
    12976
    12977 *result = SCIP_FEASIBLE;
    12978
    12979 SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
    12980
    12981 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
    12982 {
    12983 SCIP_Bool violated = FALSE;
    12984
    12985 SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
    12986
    12987 if( violated )
    12988 *result = SCIP_INFEASIBLE;
    12989 }
    12990
    12991 return SCIP_OKAY;
    12992}
    12993
    12994/** domain propagation method of constraint handler */
    12995static
    12996SCIP_DECL_CONSPROP(consPropCumulative)
    12997{ /*lint --e{715}*/
    12998 SCIP_CONSHDLRDATA* conshdlrdata;
    12999 SCIP_Bool cutoff;
    13000 int nchgbds;
    13001 int ndelconss;
    13002 int c;
    13003
    13004 SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
    13005
    13006 assert(conshdlr != NULL);
    13007 assert(nconss == 0 || conss != NULL);
    13008 assert(result != NULL);
    13009
    13011
    13012 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13013 assert(conshdlrdata != NULL);
    13014
    13015 nchgbds = 0;
    13016 ndelconss = 0;
    13017 cutoff = FALSE;
    13018 (*result) = SCIP_DIDNOTRUN;
    13019
    13020 /* propgate all useful constraints */
    13021 for( c = 0; c < nusefulconss && !cutoff; ++c )
    13022 {
    13023 SCIP_CONS* cons;
    13024
    13025 cons = conss[c];
    13026 assert(cons != NULL);
    13027
    13028 if( SCIPgetDepth(scip) == 0 )
    13029 {
    13031 &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
    13032
    13033 if( cutoff )
    13034 break;
    13035
    13036 if( SCIPconsIsDeleted(cons) )
    13037 continue;
    13038 }
    13039
    13040 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
    13041 }
    13042
    13043 if( !cutoff && nchgbds == 0 )
    13044 {
    13045 /* propgate all other constraints */
    13046 for( c = nusefulconss; c < nconss && !cutoff; ++c )
    13047 {
    13048 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
    13049 }
    13050 }
    13051
    13052 if( cutoff )
    13053 {
    13054 SCIPdebugMsg(scip, "detected infeasible\n");
    13055 *result = SCIP_CUTOFF;
    13056 }
    13057 else if( nchgbds > 0 )
    13058 {
    13059 SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
    13060 *result = SCIP_REDUCEDDOM;
    13061 }
    13062 else
    13063 *result = SCIP_DIDNOTFIND;
    13064
    13065 return SCIP_OKAY;
    13066}
    13067
    13068/** presolving method of constraint handler */
    13069static
    13070SCIP_DECL_CONSPRESOL(consPresolCumulative)
    13071{ /*lint --e{715}*/
    13072 SCIP_CONSHDLRDATA* conshdlrdata;
    13073 SCIP_CONS* cons;
    13074 SCIP_Bool cutoff;
    13075 SCIP_Bool unbounded;
    13076 int oldnfixedvars;
    13077 int oldnchgbds;
    13078 int oldndelconss;
    13079 int oldnaddconss;
    13080 int oldnupgdconss;
    13081 int oldnchgsides;
    13082 int oldnchgcoefs;
    13083 int c;
    13084
    13085 assert(conshdlr != NULL);
    13086 assert(scip != NULL);
    13087 assert(result != NULL);
    13088
    13090
    13091 SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
    13092
    13093 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13094 assert(conshdlrdata != NULL);
    13095
    13096 *result = SCIP_DIDNOTRUN;
    13097
    13098 oldnfixedvars = *nfixedvars;
    13099 oldnchgbds = *nchgbds;
    13100 oldnchgsides = *nchgsides;
    13101 oldnchgcoefs = *nchgcoefs;
    13102 oldnupgdconss = *nupgdconss;
    13103 oldndelconss = *ndelconss;
    13104 oldnaddconss = *naddconss;
    13105 cutoff = FALSE;
    13106 unbounded = FALSE;
    13107
    13108 /* process constraints */
    13109 for( c = 0; c < nconss && !cutoff; ++c )
    13110 {
    13111 cons = conss[c];
    13112
    13113 /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
    13114 * hmax)
    13115 */
    13116 SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
    13117
    13118 if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
    13119 {
    13120 SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
    13121 nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
    13122
    13123 if( cutoff || unbounded )
    13124 break;
    13125
    13126 if( SCIPconsIsDeleted(cons) )
    13127 continue;
    13128 }
    13129
    13130 /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
    13131 if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
    13132 {
    13133 SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
    13134 }
    13135
    13136 /* strengthen existing variable bounds using the cumulative condition */
    13137 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    13138 {
    13139 SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
    13140 }
    13141
    13142 /* propagate cumulative constraint */
    13143 SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
    13144 assert(checkDemands(scip, cons) || cutoff);
    13145 }
    13146
    13147 if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    13148 {
    13149 SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
    13150 }
    13151
    13152 /* only perform the detection of variable bounds and disjunctive constraint once */
    13153 if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
    13154 && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
    13155 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    13156 {
    13157 /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
    13158 * propagation
    13159 */
    13160 SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
    13161 conshdlrdata->detectedredundant = TRUE;
    13162 }
    13163
    13164 if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    13165 {
    13166 SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
    13167 }
    13168
    13169 SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
    13170 *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
    13171
    13172 if( cutoff )
    13173 *result = SCIP_CUTOFF;
    13174 else if( unbounded )
    13175 *result = SCIP_UNBOUNDED;
    13176 else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
    13177 || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
    13178 *result = SCIP_SUCCESS;
    13179 else
    13180 *result = SCIP_DIDNOTFIND;
    13181
    13182 return SCIP_OKAY;
    13183}
    13184
    13185/** propagation conflict resolving method of constraint handler */
    13186static
    13187SCIP_DECL_CONSRESPROP(consRespropCumulative)
    13188{ /*lint --e{715}*/
    13189 SCIP_CONSHDLRDATA* conshdlrdata;
    13190 SCIP_CONSDATA* consdata;
    13191
    13192 assert(conshdlr != NULL);
    13193 assert(scip != NULL);
    13194 assert(result != NULL);
    13195 assert(infervar != NULL);
    13196 assert(bdchgidx != NULL);
    13197
    13199
    13200 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13201 assert(conshdlrdata != NULL);
    13202
    13203 /* process constraint */
    13204 assert(cons != NULL);
    13205
    13206 consdata = SCIPconsGetData(cons);
    13207 assert(consdata != NULL);
    13208
    13209 SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
    13210 SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
    13212
    13213 SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
    13214 consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
    13215 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
    13216
    13217 return SCIP_OKAY;
    13218}
    13219
    13220/** variable rounding lock method of constraint handler */
    13221static
    13222SCIP_DECL_CONSLOCK(consLockCumulative)
    13223{ /*lint --e{715}*/
    13224 SCIP_CONSDATA* consdata;
    13225 SCIP_VAR** vars;
    13226 int v;
    13227
    13228 SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
    13229
    13230 assert(scip != NULL);
    13231 assert(cons != NULL);
    13232 assert(locktype == SCIP_LOCKTYPE_MODEL);
    13233
    13234 consdata = SCIPconsGetData(cons);
    13235 assert(consdata != NULL);
    13236
    13237 vars = consdata->vars;
    13238 assert(vars != NULL);
    13239
    13240 for( v = 0; v < consdata->nvars; ++v )
    13241 {
    13242 if( consdata->downlocks[v] && consdata->uplocks[v] )
    13243 {
    13244 /* the integer start variable should not get rounded in both direction */
    13245 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
    13246 }
    13247 else if( consdata->downlocks[v] )
    13248 {
    13249 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
    13250 }
    13251 else if( consdata->uplocks[v] )
    13252 {
    13253 SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
    13254 }
    13255 }
    13256
    13257 return SCIP_OKAY;
    13258}
    13259
    13260
    13261/** constraint display method of constraint handler */
    13262static
    13263SCIP_DECL_CONSPRINT(consPrintCumulative)
    13264{ /*lint --e{715}*/
    13265 assert(scip != NULL);
    13266 assert(conshdlr != NULL);
    13267 assert(cons != NULL);
    13268
    13269 consdataPrint(scip, SCIPconsGetData(cons), file);
    13270
    13271 return SCIP_OKAY;
    13272}
    13273
    13274/** constraint copying method of constraint handler */
    13275static
    13276SCIP_DECL_CONSCOPY(consCopyCumulative)
    13277{ /*lint --e{715}*/
    13278 SCIP_CONSDATA* sourceconsdata;
    13279 SCIP_VAR** sourcevars;
    13280 SCIP_VAR** vars;
    13281 const char* consname;
    13282
    13283 int nvars;
    13284 int v;
    13285
    13286 sourceconsdata = SCIPconsGetData(sourcecons);
    13287 assert(sourceconsdata != NULL);
    13288
    13289 /* get variables of the source constraint */
    13290 nvars = sourceconsdata->nvars;
    13291 sourcevars = sourceconsdata->vars;
    13292
    13293 (*valid) = TRUE;
    13294
    13295 if( nvars == 0 )
    13296 return SCIP_OKAY;
    13297
    13298 /* allocate buffer array */
    13299 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
    13300
    13301 for( v = 0; v < nvars && *valid; ++v )
    13302 {
    13303 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
    13304 assert(!(*valid) || vars[v] != NULL);
    13305 }
    13306
    13307 /* only create the target constraint, if all variables could be copied */
    13308 if( *valid )
    13309 {
    13310 if( name != NULL )
    13311 consname = name;
    13312 else
    13313 consname = SCIPconsGetName(sourcecons);
    13314
    13315 /* create a copy of the cumulative constraint */
    13316 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
    13317 sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
    13318 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    13319
    13320 /* adjust left side if the time axis if needed */
    13321 if( sourceconsdata->hmin > 0 )
    13322 {
    13323 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
    13324 }
    13325
    13326 /* adjust right side if the time axis if needed */
    13327 if( sourceconsdata->hmax < INT_MAX )
    13328 {
    13329 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
    13330 }
    13331 }
    13332
    13333 /* free buffer array */
    13334 SCIPfreeBufferArray(scip, &vars);
    13335
    13336 return SCIP_OKAY;
    13337}
    13338
    13339
    13340/** constraint parsing method of constraint handler */
    13341static
    13342SCIP_DECL_CONSPARSE(consParseCumulative)
    13343{ /*lint --e{715}*/
    13344 SCIP_VAR** vars;
    13345 SCIP_VAR* var;
    13346 SCIP_Real value;
    13347 char strvalue[SCIP_MAXSTRLEN];
    13348 char* endptr;
    13349 int* demands;
    13350 int* durations;
    13351 int capacity;
    13352 int duration;
    13353 int demand;
    13354 int hmin;
    13355 int hmax;
    13356 int varssize;
    13357 int nvars;
    13358
    13359 SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
    13360
    13361 *success = TRUE;
    13362
    13363 /* cutoff "cumulative" form the constraint string */
    13364 SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
    13365 str = endptr;
    13366
    13367 varssize = 100;
    13368 nvars = 0;
    13369
    13370 /* allocate buffer array for variables */
    13371 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
    13372 SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
    13373 SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
    13374
    13375 do
    13376 {
    13377 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
    13378
    13379 if( var == NULL )
    13380 {
    13381 endptr = strchr(endptr, ')');
    13382
    13383 if( endptr == NULL )
    13384 *success = FALSE;
    13385 else
    13386 str = endptr;
    13387
    13388 break;
    13389 }
    13390
    13391 str = endptr;
    13392 SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
    13393 duration = atoi(strvalue);
    13394 str = endptr;
    13395
    13396 SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
    13397 demand = atoi(strvalue);
    13398 str = endptr;
    13399
    13400 SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
    13401
    13402 vars[nvars] = var;
    13403 demands[nvars] = demand;
    13404 durations[nvars] = duration;
    13405 nvars++;
    13406 }
    13407 while( *str != ')' );
    13408
    13409 if( *success )
    13410 {
    13411 /* parse effective time window */
    13412 SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
    13413 hmin = atoi(strvalue);
    13414 str = endptr;
    13415
    13416 if( SCIPparseReal(scip, str, &value, &endptr) )
    13417 {
    13418 hmax = boundedConvertRealToInt(scip, value);
    13419 str = endptr;
    13420
    13421 /* parse capacity */
    13422 SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
    13423 str = endptr;
    13424 if( SCIPparseReal(scip, str, &value, &endptr) )
    13425 {
    13426 capacity = (int)value;
    13427
    13428 /* create cumulative constraint */
    13429 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
    13430 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    13431
    13432 SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
    13433 SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
    13434 }
    13435 }
    13436 }
    13437
    13438 /* free buffer arrays */
    13439 SCIPfreeBufferArray(scip, &durations);
    13440 SCIPfreeBufferArray(scip, &demands);
    13441 SCIPfreeBufferArray(scip, &vars);
    13442
    13443 return SCIP_OKAY;
    13444}
    13445
    13446
    13447/** constraint method of constraint handler which returns the variables (if possible) */
    13448static
    13449SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
    13450{ /*lint --e{715}*/
    13451 SCIP_CONSDATA* consdata;
    13452
    13453 consdata = SCIPconsGetData(cons);
    13454 assert(consdata != NULL);
    13455
    13456 if( varssize < consdata->nvars )
    13457 (*success) = FALSE;
    13458 else
    13459 {
    13460 assert(vars != NULL);
    13461
    13462 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
    13463 (*success) = TRUE;
    13464 }
    13465
    13466 return SCIP_OKAY;
    13467}
    13468
    13469/** constraint method of constraint handler which returns the number of variables (if possible) */
    13470static
    13471SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
    13472{ /*lint --e{715}*/
    13473 SCIP_CONSDATA* consdata;
    13474
    13475 consdata = SCIPconsGetData(cons);
    13476 assert(consdata != NULL);
    13477
    13478 (*nvars) = consdata->nvars;
    13479 (*success) = TRUE;
    13480
    13481 return SCIP_OKAY;
    13482}
    13483
    13484/**@} */
    13485
    13486/**@name Callback methods of event handler
    13487 *
    13488 * @{
    13489 */
    13490
    13491
    13492/** execution method of event handler */
    13493static
    13494SCIP_DECL_EVENTEXEC(eventExecCumulative)
    13495{ /*lint --e{715}*/
    13496 SCIP_CONSDATA* consdata;
    13497
    13498 assert(scip != NULL);
    13499 assert(eventhdlr != NULL);
    13500 assert(eventdata != NULL);
    13501 assert(event != NULL);
    13502
    13504
    13505 consdata = (SCIP_CONSDATA*)eventdata;
    13506 assert(consdata != NULL);
    13507
    13508 /* mark the constraint to be not propagated */
    13509 consdata->propagated = FALSE;
    13510
    13511 return SCIP_OKAY;
    13512}
    13513
    13514/**@} */
    13515
    13516/*
    13517 * constraint specific interface methods
    13518 */
    13519
    13520/** creates the handler for cumulative constraints and includes it in SCIP */
    13522 SCIP* scip /**< SCIP data structure */
    13523 )
    13524{
    13525 SCIP_CONSHDLRDATA* conshdlrdata;
    13526 SCIP_CONSHDLR* conshdlr;
    13527 SCIP_EVENTHDLR* eventhdlr;
    13528
    13529 /* create event handler for bound change events */
    13530 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
    13531
    13532 /* create cumulative constraint handler data */
    13533 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
    13534
    13535 /* include constraint handler */
    13538 consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
    13539 conshdlrdata) );
    13540
    13541 assert(conshdlr != NULL);
    13542
    13543 /* set non-fundamental callbacks via specific setter functions */
    13544 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
    13545 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
    13546#ifdef SCIP_STATISTIC
    13547 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
    13548#endif
    13549 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
    13550 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
    13551 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
    13552 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
    13553 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
    13554 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
    13555 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
    13556 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
    13558 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
    13561 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
    13562 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
    13564 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
    13565 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
    13566
    13567 /* add cumulative constraint handler parameters */
    13569 "constraints/" CONSHDLR_NAME "/maxtime", "maximum range for time horizon",
    13570 &conshdlrdata->maxtime, TRUE, DEFAULT_MAXTIME, 0, INT_MAX, NULL, NULL) );
    13572 "constraints/" CONSHDLR_NAME "/ttinfer",
    13573 "should time-table (core-times) propagator be used to infer bounds?",
    13574 &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
    13576 "constraints/" CONSHDLR_NAME "/efcheck",
    13577 "should edge-finding be used to detect an overload?",
    13578 &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
    13580 "constraints/" CONSHDLR_NAME "/efinfer",
    13581 "should edge-finding be used to infer bounds?",
    13582 &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
    13584 "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
    13585 &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
    13587 "constraints/" CONSHDLR_NAME "/ttefcheck",
    13588 "should time-table edge-finding be used to detect an overload?",
    13589 &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
    13591 "constraints/" CONSHDLR_NAME "/ttefinfer",
    13592 "should time-table edge-finding be used to infer bounds?",
    13593 &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
    13594
    13596 "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
    13597 &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
    13599 "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
    13600 &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
    13602 "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
    13603 &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
    13605 "constraints/" CONSHDLR_NAME "/cutsasconss",
    13606 "should the cumulative constraint create cuts as knapsack constraints?",
    13607 &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
    13609 "constraints/" CONSHDLR_NAME "/sepaold",
    13610 "shall old sepa algo be applied?",
    13611 &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
    13612
    13614 "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
    13615 &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
    13616
    13617 /* presolving parameters */
    13619 "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
    13620 &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
    13622 "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
    13623 &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
    13625 "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
    13626 &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
    13628 "constraints/" CONSHDLR_NAME "/presolpairwise",
    13629 "should pairwise constraint comparison be performed in presolving?",
    13630 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
    13632 "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
    13633 &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
    13634
    13636 "constraints/" CONSHDLR_NAME "/maxnodes",
    13637 "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
    13638 &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
    13640 "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
    13641 &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
    13643 "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
    13644 &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
    13645
    13646 /* conflict analysis parameters */
    13648 "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
    13649 &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
    13650
    13651 return SCIP_OKAY;
    13652}
    13653
    13654/** creates and captures a cumulative constraint */
    13656 SCIP* scip, /**< SCIP data structure */
    13657 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13658 const char* name, /**< name of constraint */
    13659 int nvars, /**< number of variables (jobs) */
    13660 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    13661 int* durations, /**< array containing corresponding durations */
    13662 int* demands, /**< array containing corresponding demands */
    13663 int capacity, /**< available cumulative capacity */
    13664 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    13665 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    13666 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    13667 * Usually set to TRUE. */
    13668 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    13669 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    13670 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    13671 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    13672 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    13673 * Usually set to TRUE. */
    13674 SCIP_Bool local, /**< is constraint only valid locally?
    13675 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    13676 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    13677 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    13678 * adds coefficients to this constraint. */
    13679 SCIP_Bool dynamic, /**< is constraint subject to aging?
    13680 * Usually set to FALSE. Set to TRUE for own cuts which
    13681 * are seperated as constraints. */
    13682 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    13683 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    13684 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    13685 * if it may be moved to a more global node?
    13686 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    13687 )
    13688{
    13689 int i;
    13690 SCIP_CONSHDLR* conshdlr;
    13691 SCIP_CONSDATA* consdata;
    13692
    13693 assert(scip != NULL);
    13694
    13695 /* find the cumulative constraint handler */
    13696 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    13697 if( conshdlr == NULL )
    13698 {
    13699 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
    13700 return SCIP_PLUGINNOTFOUND;
    13701 }
    13702
    13703 for( i = 0; i < nvars; ++i )
    13704 {
    13705 if( INT_MAX - durations[i] < boundedConvertRealToInt(scip, SCIPvarGetUbGlobal(vars[i])) )
    13706 {
    13707 SCIPerrorMessage("detected potential integer overflow for variable <%s> in constraint <%s>: "
    13708 "decrease upper bound of variable or time horizon constraints/" CONSHDLR_NAME "/maxtime\n",
    13709 name, SCIPvarGetName(vars[i]));
    13710 return SCIP_INVALIDDATA;
    13711 }
    13712 }
    13713 SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
    13714
    13715 /* create constraint data */
    13716 SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
    13717
    13718 /* create constraint */
    13719 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
    13720 initial, separate, enforce, check, propagate,
    13721 local, modifiable, dynamic, removable, stickingatnode) );
    13722
    13724 {
    13725 SCIP_CONSHDLRDATA* conshdlrdata;
    13726
    13727 /* get event handler */
    13728 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13729 assert(conshdlrdata != NULL);
    13730 assert(conshdlrdata->eventhdlr != NULL);
    13731
    13732 /* catch bound change events of variables */
    13733 SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
    13734 }
    13735
    13736 return SCIP_OKAY;
    13737}
    13738
    13739/** creates and captures a cumulative constraint
    13740 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
    13741 * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
    13742 *
    13743 * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
    13744 *
    13745 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13746 */
    13748 SCIP* scip, /**< SCIP data structure */
    13749 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13750 const char* name, /**< name of constraint */
    13751 int nvars, /**< number of variables (jobs) */
    13752 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    13753 int* durations, /**< array containing corresponding durations */
    13754 int* demands, /**< array containing corresponding demands */
    13755 int capacity /**< available cumulative capacity */
    13756 )
    13757{
    13758 assert(scip != NULL);
    13759
    13760 SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
    13762
    13763 return SCIP_OKAY;
    13764}
    13765
    13766/** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
    13768 SCIP* scip, /**< SCIP data structure */
    13769 SCIP_CONS* cons, /**< constraint data */
    13770 int hmin /**< left bound of time axis to be considered */
    13771 )
    13772{
    13773 SCIP_CONSDATA* consdata;
    13774
    13776
    13777 consdata = SCIPconsGetData(cons);
    13778 assert(consdata != NULL);
    13779
    13780 if( hmin < 0 || hmin > consdata->hmax )
    13781 {
    13782 SCIPerrorMessage("invalid value of hmin for cumulative constraint <%s>\n",
    13783 SCIPconsGetName(cons));
    13784 return SCIP_INVALIDCALL;
    13785 }
    13786
    13787 consdata->hmin = hmin;
    13788
    13789 return SCIP_OKAY;
    13790}
    13791
    13792/** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
    13794 SCIP* scip, /**< SCIP data structure */
    13795 SCIP_CONS* cons /**< constraint */
    13796 )
    13797{
    13798 SCIP_CONSDATA* consdata;
    13799
    13801
    13802 consdata = SCIPconsGetData(cons);
    13803 assert(consdata != NULL);
    13804
    13805 return consdata->hmin;
    13806}
    13807
    13808/** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
    13810 SCIP* scip, /**< SCIP data structure */
    13811 SCIP_CONS* cons, /**< constraint data */
    13812 int hmax /**< right bound of time axis to be considered */
    13813 )
    13814{
    13815 SCIP_CONSDATA* consdata;
    13816
    13818
    13819 consdata = SCIPconsGetData(cons);
    13820 assert(consdata != NULL);
    13821
    13822 if( hmax < consdata->hmin )
    13823 {
    13824 SCIPerrorMessage("invalid value of hmax for cumulative constraint <%s>\n",
    13825 SCIPconsGetName(cons));
    13826 return SCIP_INVALIDCALL;
    13827 }
    13828
    13829 consdata->hmax = hmax;
    13830
    13831 return SCIP_OKAY;
    13832}
    13833
    13834/** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
    13836 SCIP* scip, /**< SCIP data structure */
    13837 SCIP_CONS* cons /**< constraint */
    13838 )
    13839{
    13840 SCIP_CONSDATA* consdata;
    13841
    13843
    13844 consdata = SCIPconsGetData(cons);
    13845 assert(consdata != NULL);
    13846
    13847 return consdata->hmax;
    13848}
    13849
    13850/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
    13852 SCIP* scip, /**< SCIP data structure */
    13853 SCIP_CONS* cons /**< constraint data */
    13854 )
    13855{
    13856 SCIP_CONSDATA* consdata;
    13857
    13859
    13860 consdata = SCIPconsGetData(cons);
    13861 assert(consdata != NULL);
    13862
    13863 return consdata->vars;
    13864}
    13865
    13866/** returns the activities of the cumulative constraint */ /*lint -e{715}*/
    13868 SCIP* scip, /**< SCIP data structure */
    13869 SCIP_CONS* cons /**< constraint data */
    13870 )
    13871{
    13872 SCIP_CONSDATA* consdata;
    13873
    13875
    13876 consdata = SCIPconsGetData(cons);
    13877 assert(consdata != NULL);
    13878
    13879 return consdata->nvars;
    13880}
    13881
    13882/** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
    13884 SCIP* scip, /**< SCIP data structure */
    13885 SCIP_CONS* cons /**< constraint data */
    13886 )
    13887{
    13888 SCIP_CONSDATA* consdata;
    13889
    13891
    13892 consdata = SCIPconsGetData(cons);
    13893 assert(consdata != NULL);
    13894
    13895 return consdata->capacity;
    13896}
    13897
    13898/** returns the durations of the cumulative constraint */ /*lint -e{715}*/
    13900 SCIP* scip, /**< SCIP data structure */
    13901 SCIP_CONS* cons /**< constraint data */
    13902 )
    13903{
    13904 SCIP_CONSDATA* consdata;
    13905
    13907
    13908 consdata = SCIPconsGetData(cons);
    13909 assert(consdata != NULL);
    13910
    13911 return consdata->durations;
    13912}
    13913
    13914/** returns the demands 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
    13923
    13924 consdata = SCIPconsGetData(cons);
    13925 assert(consdata != NULL);
    13926
    13927 return consdata->demands;
    13928}
    13929
    13930/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
    13931 * given solution is satisfied
    13932 */
    13934 SCIP* scip, /**< SCIP data structure */
    13935 SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
    13936 int nvars, /**< number of variables (jobs) */
    13937 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    13938 int* durations, /**< array containing corresponding durations */
    13939 int* demands, /**< array containing corresponding demands */
    13940 int capacity, /**< available cumulative capacity */
    13941 int hmin, /**< left bound of time axis to be considered (including hmin) */
    13942 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    13943 SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
    13944 SCIP_CONS* cons, /**< constraint which is checked */
    13945 SCIP_Bool printreason /**< should the reason for the violation be printed? */
    13946 )
    13947{
    13948 assert(scip != NULL);
    13949 assert(violated != NULL);
    13950
    13951 SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
    13952 violated, cons, printreason) );
    13953
    13954 return SCIP_OKAY;
    13955}
    13956
    13957/** normalize cumulative condition */ /*lint -e{715}*/
    13959 SCIP* scip, /**< SCIP data structure */
    13960 int nvars, /**< number of start time variables (activities) */
    13961 SCIP_VAR** vars, /**< array of start time variables */
    13962 int* durations, /**< array of durations */
    13963 int* demands, /**< array of demands */
    13964 int* capacity, /**< pointer to store the changed cumulative capacity */
    13965 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    13966 int* nchgsides /**< pointer to count number of side changes */
    13967 )
    13968{ /*lint --e{715}*/
    13969 normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
    13970
    13971 return SCIP_OKAY;
    13972}
    13973
    13974/** searches for a time point within the cumulative condition were the cumulative condition can be split */
    13976 SCIP* scip, /**< SCIP data structure */
    13977 int nvars, /**< number of variables (jobs) */
    13978 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    13979 int* durations, /**< array containing corresponding durations */
    13980 int* demands, /**< array containing corresponding demands */
    13981 int capacity, /**< available cumulative capacity */
    13982 int* hmin, /**< pointer to store the left bound of the effective horizon */
    13983 int* hmax, /**< pointer to store the right bound of the effective horizon */
    13984 int* split /**< point were the cumulative condition can be split */
    13985 )
    13986{
    13987 SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
    13988 hmin, hmax, split) );
    13989
    13990 return SCIP_OKAY;
    13991}
    13992
    13993/** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
    13995 SCIP* scip, /**< SCIP data structure */
    13996 int nvars, /**< number of start time variables (activities) */
    13997 SCIP_VAR** vars, /**< array of start time variables */
    13998 int* durations, /**< array of durations */
    13999 int hmin, /**< left bound of time axis to be considered */
    14000 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    14001 SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
    14002 SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
    14003 SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
    14004 SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
    14005 int* nfixedvars, /**< pointer to store the number of fixed variables */
    14006 int* nchgsides, /**< pointer to store the number of changed sides */
    14007 SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
    14008 )
    14009{
    14010 if( nvars <= 1 )
    14011 return SCIP_OKAY;
    14012
    14013 /* presolve constraint form the earlier start time point of view */
    14014 SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
    14015 irrelevants, nfixedvars, nchgsides, cutoff) );
    14016
    14017 /* presolve constraint form the latest completion time point of view */
    14018 SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
    14019 irrelevants, nfixedvars, nchgsides, cutoff) );
    14020
    14021 return SCIP_OKAY;
    14022}
    14023
    14024/** propagate the given cumulative condition */
    14026 SCIP* scip, /**< SCIP data structure */
    14027 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
    14028 int nvars, /**< number of variables (jobs) */
    14029 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    14030 int* durations, /**< array containing corresponding durations */
    14031 int* demands, /**< array containing corresponding demands */
    14032 int capacity, /**< available cumulative capacity */
    14033 int hmin, /**< left bound of time axis to be considered (including hmin) */
    14034 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    14035 SCIP_CONS* cons, /**< constraint which gets propagated */
    14036 int* nchgbds, /**< pointer to store the number of variable bound changes */
    14037 SCIP_Bool* initialized, /**< was conflict analysis initialized */
    14038 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    14039 SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
    14040 )
    14041{
    14042 SCIP_CONSHDLR* conshdlr;
    14043 SCIP_CONSHDLRDATA* conshdlrdata;
    14044 SCIP_Bool redundant;
    14045
    14046 assert(scip != NULL);
    14047 assert(cons != NULL);
    14048 assert(initialized != NULL);
    14049 assert(*initialized == FALSE);
    14050 assert(cutoff != NULL);
    14051 assert(*cutoff == FALSE);
    14052
    14053 /* find the cumulative constraint handler */
    14054 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    14055 if( conshdlr == NULL )
    14056 {
    14057 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
    14058 return SCIP_PLUGINNOTFOUND;
    14059 }
    14060
    14061 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    14062 assert(conshdlrdata != NULL);
    14063
    14064 redundant = FALSE;
    14065
    14066 SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
    14067 nvars, vars, durations, demands, capacity, hmin, hmax, cons,
    14068 nchgbds, &redundant, initialized, explanation, cutoff) );
    14069
    14070 return SCIP_OKAY;
    14071}
    14072
    14073/** resolve propagation w.r.t. the cumulative condition */
    14075 SCIP* scip, /**< SCIP data structure */
    14076 int nvars, /**< number of start time variables (activities) */
    14077 SCIP_VAR** vars, /**< array of start time variables */
    14078 int* durations, /**< array of durations */
    14079 int* demands, /**< array of demands */
    14080 int capacity, /**< cumulative capacity */
    14081 int hmin, /**< left bound of time axis to be considered (including hmin) */
    14082 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    14083 SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
    14084 int inferinfo, /**< the user information */
    14085 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
    14086 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
    14087 SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
    14088 SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
    14089 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
    14090 )
    14091{
    14092 SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
    14093 infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
    14094
    14095 return SCIP_OKAY;
    14096}
    14097
    14098/** this method visualizes the cumulative structure in GML format */
    14100 SCIP* scip, /**< SCIP data structure */
    14101 SCIP_CONS* cons /**< cumulative constraint */
    14102 )
    14103{
    14104 SCIP_CONSDATA* consdata;
    14105 SCIP_HASHTABLE* vars;
    14106 FILE* file;
    14107 SCIP_VAR* var;
    14108 char filename[SCIP_MAXSTRLEN];
    14109 int nvars;
    14110 int v;
    14111
    14112 SCIP_RETCODE retcode = SCIP_OKAY;
    14113
    14114 /* open file */
    14115 (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
    14116 file = fopen(filename, "w");
    14117
    14118 /* check if the file was open */
    14119 if( file == NULL )
    14120 {
    14121 SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
    14122 SCIPprintSysError(filename);
    14123 return SCIP_FILECREATEERROR;
    14124 }
    14125
    14126 consdata = SCIPconsGetData(cons);
    14127 assert(consdata != NULL);
    14128
    14129 nvars = consdata->nvars;
    14130
    14131 SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
    14132 SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
    14133
    14134 /* create opening of the GML format */
    14136
    14137 for( v = 0; v < nvars; ++v )
    14138 {
    14139 char color[SCIP_MAXSTRLEN];
    14140
    14141 var = consdata->vars[v];
    14142 assert(var != NULL);
    14143
    14144 SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
    14145
    14146 if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
    14147 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
    14148 else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
    14149 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
    14150 else
    14151 (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
    14152
    14153 SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
    14154 }
    14155
    14156 for( v = 0; v < nvars; ++v )
    14157 {
    14158 SCIP_VAR** vbdvars;
    14159 int nvbdvars;
    14160 int b;
    14161
    14162 var = consdata->vars[v];
    14163 assert(var != NULL);
    14164
    14165 vbdvars = SCIPvarGetVlbVars(var);
    14166 nvbdvars = SCIPvarGetNVlbs(var);
    14167
    14168 for( b = 0; b < nvbdvars; ++b )
    14169 {
    14170 if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
    14171 {
    14172 SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
    14173 }
    14174 }
    14175
    14176#ifdef SCIP_MORE_OUTPUT
    14177 /* define to also output variable bounds */
    14178 vbdvars = SCIPvarGetVubVars(var);
    14179 nvbdvars = SCIPvarGetNVubs(var);
    14180
    14181 for( b = 0; b < nvbdvars; ++b )
    14182 {
    14183 if( SCIPhashtableExists(vars, vbdvars[b]) )
    14184 {
    14185 SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
    14186 }
    14187 }
    14188#endif
    14189 }
    14190
    14191 /* create closing of the GML format */
    14192 SCIPgmlWriteClosing(file);
    14193TERMINATE:
    14194 /* close file */
    14195 fclose(file);
    14196
    14197 SCIPhashtableFree(&vars);
    14198
    14199 return retcode;
    14200}
    14201
    14202/** sets method to solve an individual cumulative condition */
    14204 SCIP* scip, /**< SCIP data structure */
    14205 SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
    14206 )
    14207{
    14208 SCIP_CONSHDLR* conshdlr;
    14209 SCIP_CONSHDLRDATA* conshdlrdata;
    14210
    14211 /* find the cumulative constraint handler */
    14212 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    14213 if( conshdlr == NULL )
    14214 {
    14215 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
    14216 return SCIP_PLUGINNOTFOUND;
    14217 }
    14218
    14219 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    14220 assert(conshdlrdata != NULL);
    14221
    14222 conshdlrdata->solveCumulative = solveCumulative;
    14223
    14224 return SCIP_OKAY;
    14225}
    14226
    14227/** solves given cumulative condition as independent sub problem
    14228 *
    14229 * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
    14230 * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
    14231 * solver was interrupted.
    14232 */
    14234 SCIP* scip, /**< SCIP data structure */
    14235 int njobs, /**< number of jobs (activities) */
    14236 SCIP_Real* ests, /**< array with the earlier start time for each job */
    14237 SCIP_Real* lsts, /**< array with the latest start time for each job */
    14238 SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
    14239 int* durations, /**< array of durations */
    14240 int* demands, /**< array of demands */
    14241 int capacity, /**< cumulative capacity */
    14242 int hmin, /**< left bound of time axis to be considered (including hmin) */
    14243 int hmax, /**< right bound of time axis to be considered (not including hmax) */
    14244 SCIP_Real timelimit, /**< time limit for solving in seconds */
    14245 SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
    14246 SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
    14247 SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
    14248 SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
    14249 SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
    14250 SCIP_Bool* error /**< pointer to store if an error occurred */
    14251 )
    14252{
    14253 SCIP_CONSHDLR* conshdlr;
    14254 SCIP_CONSHDLRDATA* conshdlrdata;
    14255
    14256 (*solved) = TRUE;
    14257 (*infeasible) = FALSE;
    14258 (*unbounded) = FALSE;
    14259 (*error) = FALSE;
    14260
    14261 if( njobs == 0 )
    14262 return SCIP_OKAY;
    14263
    14264 /* find the cumulative constraint handler */
    14265 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    14266 if( conshdlr == NULL )
    14267 {
    14268 SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
    14269 (*error) = TRUE;
    14270 return SCIP_PLUGINNOTFOUND;
    14271 }
    14272
    14273 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    14274 assert(conshdlrdata != NULL);
    14275
    14276 /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
    14277 if( timelimit > 0.0 && memorylimit > 10 )
    14278 {
    14279 SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
    14280 hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
    14281 }
    14282
    14283 return SCIP_OKAY;
    14284}
    14285
    14286/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
    14287 * completion time
    14288 */
    14290 SCIP* scip, /**< SCIP data structure */
    14291 SCIP_PROFILE* profile, /**< resource profile */
    14292 int nvars, /**< number of variables (jobs) */
    14293 SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
    14294 int* durations, /**< array containing corresponding durations */
    14295 int* demands /**< array containing corresponding demands */
    14296 )
    14297{
    14298 SCIP_VAR* var;
    14299 SCIP_HASHMAP* addedvars;
    14300 int* copydemands;
    14301 int* perm;
    14302 int duration;
    14303 int impliedest;
    14304 int est;
    14305 int impliedlct;
    14306 int lct;
    14307 int v;
    14308
    14309 /* create hash map for variables which are added, mapping to their duration */
    14310 SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
    14311
    14312 SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
    14313 SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
    14314
    14315 /* sort variables w.r.t. job demands */
    14316 for( v = 0; v < nvars; ++v )
    14317 {
    14318 copydemands[v] = demands[v];
    14319 perm[v] = v;
    14320 }
    14321 SCIPsortDownIntInt(copydemands, perm, nvars);
    14322
    14323 /* add each job with its earliest start and latest completion time into the resource profile */
    14324 for( v = 0; v < nvars; ++v )
    14325 {
    14326 int idx;
    14327
    14328 idx = perm[v];
    14329 assert(idx >= 0 && idx < nvars);
    14330
    14331 var = vars[idx];
    14332 assert(var != NULL);
    14333
    14334 duration = durations[idx];
    14335 assert(duration > 0);
    14336
    14338 SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
    14339
    14340 lct = boundedConvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
    14341 SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
    14342
    14343 if( impliedest < impliedlct )
    14344 {
    14345 SCIP_Bool infeasible;
    14346 int pos;
    14347
    14348 SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
    14349 assert(!infeasible);
    14350 assert(pos == -1);
    14351 }
    14352
    14353 if( est == impliedest && lct == impliedlct )
    14354 {
    14355 SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
    14356 }
    14357 }
    14358
    14359 SCIPfreeBufferArray(scip, &copydemands);
    14360 SCIPfreeBufferArray(scip, &perm);
    14361
    14362 SCIPhashmapFree(&addedvars);
    14363
    14364 return SCIP_OKAY;
    14365}
    14366
    14367/** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
    14369 SCIP* scip, /**< SCIP data structure */
    14370 SCIP_PROFILE* profile, /**< worst case resource profile */
    14371 int capacity /**< capacity to check */
    14372 )
    14373{
    14374 int* timepoints;
    14375 int* loads;
    14376 int ntimepoints;
    14377 int t;
    14378
    14379 ntimepoints = SCIPprofileGetNTimepoints(profile);
    14380 timepoints = SCIPprofileGetTimepoints(profile);
    14381 loads = SCIPprofileGetLoads(profile);
    14382
    14383 /* find first time point which potentially violates the capacity restriction */
    14384 for( t = 0; t < ntimepoints - 1; ++t )
    14385 {
    14386 /* check if the time point exceed w.r.t. worst case profile the capacity */
    14387 if( loads[t] > capacity )
    14388 {
    14389 assert(t == 0 || loads[t-1] <= capacity);
    14390 return timepoints[t];
    14391 }
    14392 }
    14393
    14394 return INT_MAX;
    14395}
    14396
    14397/** 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}*/
    14399 SCIP* scip, /**< SCIP data structure */
    14400 SCIP_PROFILE* profile, /**< worst case profile */
    14401 int capacity /**< capacity to check */
    14402 )
    14403{
    14404 int* timepoints;
    14405 int* loads;
    14406 int ntimepoints;
    14407 int t;
    14408
    14409 ntimepoints = SCIPprofileGetNTimepoints(profile);
    14410 timepoints = SCIPprofileGetTimepoints(profile);
    14411 loads = SCIPprofileGetLoads(profile);
    14412
    14413 /* find last time point which potentially violates the capacity restriction */
    14414 for( t = ntimepoints - 1; t >= 0; --t )
    14415 {
    14416 /* check if at time point t the worst case resource profile exceeds the capacity */
    14417 if( loads[t] > capacity )
    14418 {
    14419 assert(t == ntimepoints-1 || loads[t+1] <= capacity);
    14420 return timepoints[t+1];
    14421 }
    14422 }
    14423
    14424 return INT_MIN;
    14425}
    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:172
    Proprule
    Definition: cons_and.c:165
    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:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define SCIP_UNKNOWN
    Definition: def.h:188
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_CALL_TERMINATE(retcode, x, TERM)
    Definition: def.h:385
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define MIN3(x, y, z)
    Definition: def.h:241
    #define SCIPABORT()
    Definition: def.h:336
    #define SCIP_LONGINT_MAX
    Definition: def.h:151
    #define SCIP_CALL(x)
    Definition: def.h:364
    #define SCIP_CALL_FINALLY(x, y)
    Definition: def.h:406
    #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:9533
    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:9664
    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:655
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    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:4350
    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:4320
    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:4340
    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:8423
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8652
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8413
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8562
    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:8592
    SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
    Definition: cons.c:8522
    SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
    Definition: cons.c:8702
    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:8582
    SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
    Definition: cons.c:8454
    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:8612
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8632
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8393
    SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1812
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8642
    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:8672
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8572
    SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1138
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8662
    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:2986
    void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
    Definition: scip_sol.c:451
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
    Definition: scip_solve.c:3616
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2611
    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:23546
    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:24514
    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:24536
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23674
    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:23418
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4380
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
    Definition: var.c:23462
    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:23932
    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:23485
    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:24174
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23684
    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:23694
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
    Definition: var.c:24546
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24556
    SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
    Definition: var.c:23556
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24526
    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:24152
    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:17319
    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:24588
    SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
    Definition: var.c:24568
    SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
    Definition: var.c:24578
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4322
    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:1219
    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