SCIP

    Solving Constraint Integer Programs

    cons_knapsack.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_knapsack.c
    26 * @ingroup DEFPLUGINS_CONS
    27 * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
    28 * @author Tobias Achterberg
    29 * @author Xin Liu
    30 * @author Kati Wolter
    31 * @author Michael Winkler
    32 * @author Tobias Fischer
    33 */
    34
    35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    36
    38#include "scip/cons_knapsack.h"
    39#include "scip/cons_linear.h"
    40#include "scip/cons_logicor.h"
    41#include "scip/cons_setppc.h"
    42#include "scip/pub_cons.h"
    43#include "scip/pub_event.h"
    44#include "scip/pub_implics.h"
    45#include "scip/pub_lp.h"
    46#include "scip/pub_message.h"
    47#include "scip/pub_misc.h"
    49#include "scip/pub_misc_sort.h"
    50#include "scip/pub_sepa.h"
    51#include "scip/pub_var.h"
    52#include "scip/scip_branch.h"
    53#include "scip/scip_conflict.h"
    54#include "scip/scip_cons.h"
    55#include "scip/scip_copy.h"
    56#include "scip/scip_cut.h"
    57#include "scip/scip_event.h"
    58#include "scip/scip_general.h"
    59#include "scip/scip_lp.h"
    60#include "scip/scip_mem.h"
    61#include "scip/scip_message.h"
    62#include "scip/scip_nlp.h"
    63#include "scip/scip_numerics.h"
    64#include "scip/scip_param.h"
    65#include "scip/scip_prob.h"
    66#include "scip/scip_probing.h"
    67#include "scip/scip_sol.h"
    69#include "scip/scip_tree.h"
    70#include "scip/scip_var.h"
    71#include "scip/symmetry_graph.h"
    73#include <ctype.h>
    74#include <string.h>
    75
    76#ifdef WITH_CARDINALITY_UPGRADE
    78#endif
    79
    80/* constraint handler properties */
    81#define CONSHDLR_NAME "knapsack"
    82#define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
    83#define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
    84#define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
    85#define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
    86#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
    87#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
    88#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
    89 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
    90#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
    91#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
    92#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
    93#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
    94
    95#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
    96#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
    97
    98#define EVENTHDLR_NAME "knapsack"
    99#define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
    100#define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
    101 | SCIP_EVENTTYPE_UBTIGHTENED \
    102 | SCIP_EVENTTYPE_VARFIXED \
    103 | SCIP_EVENTTYPE_VARDELETED \
    104 | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
    105
    106#define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
    107
    108#define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
    109#define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
    110
    111#define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
    112#define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
    113#define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
    114
    115#define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
    116#define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
    117#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
    118#define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
    119#define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
    120#define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
    121 * to best node's dual bound for separating knapsack cuts */
    122#define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
    123#define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
    124#define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
    125
    126#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
    127#define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
    128
    129#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
    130#define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
    131
    132#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
    133#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
    134#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
    135 * comparison round */
    136#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
    137#define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
    138 * function defining an upper bound and prevent these constraints from
    139 * entering the LP */
    140#define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
    141 * function defining a lower bound and prevent these constraints from
    142 * entering the LP */
    143#define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
    144#define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
    145
    146#define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
    147#define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
    148#define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
    149#define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
    150 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
    151#define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
    152#define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
    153#ifdef WITH_CARDINALITY_UPGRADE
    154#define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
    155#endif
    156
    157/* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
    158
    159/*
    160 * Data structures
    161 */
    162
    163/** constraint handler data */
    164struct SCIP_ConshdlrData
    165{
    166 int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
    167 * you have to clear it at the end, exists only in presolving stage */
    168 int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
    169 * you have to clear it at the end, exists only in presolving stage */
    170 SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
    171 * you have to clear it at the end, exists only in presolving stage */
    172 SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
    173 * you have to clear it at the end, exists only in presolving stage */
    174 SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
    175 * you have to clear it at the end, exists only in presolving stage */
    176 SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
    177 * you have to clear it at the end, exists only in presolving stage */
    178 SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
    179 * you have to clear it at the end, exists only in presolving stage */
    180 SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
    181 * you have to clear it at the end, exists only in presolving stage */
    182 SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
    183 * you have to clear it at the end */
    184 int ints1size; /**< size of ints1 array */
    185 int ints2size; /**< size of ints2 array */
    186 int longints1size; /**< size of longints1 array */
    187 int longints2size; /**< size of longints2 array */
    188 int bools1size; /**< size of bools1 array */
    189 int bools2size; /**< size of bools2 array */
    190 int bools3size; /**< size of bools3 array */
    191 int bools4size; /**< size of bools4 array */
    192 int reals1size; /**< size of reals1 array */
    193 int* probtoidxmap; /**< cleared memory array with default values -1; used for clique partitions */
    194 int probtoidxmapsize; /**< size of probtoidxmap */
    195 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
    196 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
    197 * to best node's dual bound for separating knapsack cuts */
    198 int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
    199 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
    200 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
    201 int maxsepacuts; /**< maximal number of cuts separated per separation round */
    202 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
    203 SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
    204 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
    205 SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
    206 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
    207 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
    208 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
    209 SCIP_Bool usegubs; /**< should GUB information be used for separation? */
    210 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
    211 * function defining an upper bound and prevent these constraints from
    212 * entering the LP */
    213 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
    214 * function defining a lower bound and prevent these constraints from
    215 * entering the LP */
    216 SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
    217 SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
    218 SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
    219 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
    220#ifdef WITH_CARDINALITY_UPGRADE
    221 SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
    222 SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
    223#endif
    224};
    225
    226
    227/** constraint data for knapsack constraints */
    228struct SCIP_ConsData
    229{
    230 SCIP_VAR** vars; /**< variables in knapsack constraint */
    231 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
    232 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
    233 int* cliquepartition; /**< clique indices of the clique partition */
    234 int* negcliquepartition; /**< clique indices of the negated clique partition */
    235 SCIP_ROW* row; /**< corresponding LP row */
    236 SCIP_NLROW* nlrow; /**< corresponding NLP row */
    237 int nvars; /**< number of variables in knapsack constraint */
    238 int varssize; /**< size of vars, weights, and eventdata arrays */
    239 int ncliques; /**< number of cliques in the clique partition */
    240 int nnegcliques; /**< number of cliques in the negated clique partition */
    241 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
    242 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
    243 SCIP_Longint capacity; /**< capacity of knapsack */
    244 SCIP_Longint weightsum; /**< sum of all weights */
    245 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
    246 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
    247 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
    248 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
    249 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
    250 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
    251 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
    252 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
    253 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
    254};
    255
    256/** event data for bound changes events */
    257struct SCIP_EventData
    258{
    259 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
    260 SCIP_Longint weight; /**< weight of variable */
    261 int filterpos; /**< position of event in variable's event filter */
    262};
    263
    264
    265/** data structure to combine two sorting key values */
    266struct sortkeypair
    267{
    268 SCIP_Real key1; /**< first sort key value */
    269 SCIP_Real key2; /**< second sort key value */
    270};
    271typedef struct sortkeypair SORTKEYPAIR;
    272
    273/** status of GUB constraint */
    275{
    276 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
    277 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
    278 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
    279 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
    280 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
    281 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
    284
    285/** status of variable in GUB constraint */
    287{
    288 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
    289 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
    290 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
    291 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
    292 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
    293 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
    296
    297/** data structure of GUB constraints */
    299{
    300 int* gubvars; /**< indices of GUB variables in knapsack constraint */
    301 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
    302 int ngubvars; /**< number of GUB variables */
    303 int gubvarssize; /**< size of gubvars array */
    304};
    306
    307/** data structure of a set of GUB constraints */
    309{
    310 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
    311 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
    312 int ngubconss; /**< number of GUB constraints */
    313 int nvars; /**< number of variables in knapsack constraint */
    314 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
    315 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
    316};
    318
    319/*
    320 * Local methods
    321 */
    322
    323/** comparison method for two sorting key pairs */
    324static
    325SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
    326{
    327 SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
    328 SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
    329
    330 if( sortkeypair1->key1 < sortkeypair2->key1 )
    331 return -1;
    332 else if( sortkeypair1->key1 > sortkeypair2->key1 )
    333 return +1;
    334 else if( sortkeypair1->key2 < sortkeypair2->key2 )
    335 return -1;
    336 else if( sortkeypair1->key2 > sortkeypair2->key2 )
    337 return +1;
    338 else
    339 return 0;
    340}
    341
    342/** creates event data */
    343static
    345 SCIP* scip, /**< SCIP data structure */
    346 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
    347 SCIP_CONS* cons, /**< constraint */
    348 SCIP_Longint weight /**< weight of variable */
    349 )
    350{
    351 assert(eventdata != NULL);
    352
    353 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
    354 (*eventdata)->cons = cons;
    355 (*eventdata)->weight = weight;
    356
    357 return SCIP_OKAY;
    358}
    359
    360/** frees event data */
    361static
    363 SCIP* scip, /**< SCIP data structure */
    364 SCIP_EVENTDATA** eventdata /**< pointer to event data */
    365 )
    366{
    367 assert(eventdata != NULL);
    368
    369 SCIPfreeBlockMemory(scip, eventdata);
    370
    371 return SCIP_OKAY;
    372}
    373
    374/** sorts items in knapsack with nonincreasing weights */
    375static
    377 SCIP_CONSDATA* consdata /**< constraint data */
    378 )
    379{
    380 assert(consdata != NULL);
    381 assert(consdata->nvars == 0 || consdata->vars != NULL);
    382 assert(consdata->nvars == 0 || consdata->weights != NULL);
    383 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
    384 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
    385
    386 if( !consdata->sorted )
    387 {
    388 int pos;
    389 int lastcliquenum;
    390 int v;
    391
    392 /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
    393 * sorted by first array in non-increasing order via sort template */
    395 consdata->weights,
    396 (void**)consdata->vars,
    397 (void**)consdata->eventdata,
    398 consdata->cliquepartition,
    399 consdata->negcliquepartition,
    400 consdata->nvars);
    401
    402 v = consdata->nvars - 1;
    403 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
    404 while( v >= 0 )
    405 {
    406 int w = v - 1;
    407
    408 while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
    409 --w;
    410
    411 if( v - w > 1 )
    412 {
    413 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
    415 (void**)(&(consdata->vars[w+1])),
    416 (void**)(&(consdata->eventdata[w+1])),
    417 &(consdata->cliquepartition[w+1]),
    418 &(consdata->negcliquepartition[w+1]),
    419 SCIPvarComp,
    420 v - w);
    421 }
    422 v = w;
    423 }
    424
    425 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
    426 if( consdata->cliquepartitioned )
    427 {
    428 lastcliquenum = 0;
    429
    430 for( pos = 0; pos < consdata->nvars; ++pos )
    431 {
    432 /* if the clique number in the normal clique at position pos is greater than the last found clique number the
    433 * partition is invalid */
    434 if( consdata->cliquepartition[pos] > lastcliquenum )
    435 {
    436 consdata->cliquepartitioned = FALSE;
    437 break;
    438 }
    439 else if( consdata->cliquepartition[pos] == lastcliquenum )
    440 ++lastcliquenum;
    441 }
    442 }
    443 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
    444 if( consdata->negcliquepartitioned )
    445 {
    446 lastcliquenum = 0;
    447
    448 for( pos = 0; pos < consdata->nvars; ++pos )
    449 {
    450 /* if the clique number in the negated clique at position pos is greater than the last found clique number the
    451 * partition is invalid */
    452 if( consdata->negcliquepartition[pos] > lastcliquenum )
    453 {
    454 consdata->negcliquepartitioned = FALSE;
    455 break;
    456 }
    457 else if( consdata->negcliquepartition[pos] == lastcliquenum )
    458 ++lastcliquenum;
    459 }
    460 }
    461
    462 consdata->sorted = TRUE;
    463 }
    464#ifndef NDEBUG
    465 {
    466 /* check if the weight array is sorted in a non-increasing way */
    467 int i;
    468 for( i = 0; i < consdata->nvars-1; ++i )
    469 assert(consdata->weights[i] >= consdata->weights[i+1]);
    470 }
    471#endif
    472}
    473
    474/** calculates a partition of the variables into cliques */
    475static
    477 SCIP* scip, /**< SCIP data structure */
    478 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
    479 SCIP_CONSDATA* consdata, /**< constraint data */
    480 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
    481 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
    482 )
    483{
    484 SCIP_Bool ispartitionoutdated;
    485 SCIP_Bool isnegpartitionoutdated;
    486 assert(consdata != NULL);
    487 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
    488
    489 /* rerun eventually if number of global cliques increased considerably since last partition */
    490 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
    491 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
    492
    493 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
    494 {
    495 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
    496 consdata->cliquepartition, &consdata->ncliques) );
    497 consdata->cliquepartitioned = TRUE;
    498 consdata->ncliqueslastpart = SCIPgetNCliques(scip);
    499 }
    500
    501 /* rerun eventually if number of global cliques increased considerably since last negated partition */
    502 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
    503 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
    504
    505 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
    506 {
    507 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
    508 consdata->negcliquepartition, &consdata->nnegcliques) );
    509 consdata->negcliquepartitioned = TRUE;
    510 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
    511 }
    512 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
    513 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
    514
    515 return SCIP_OKAY;
    516}
    517
    518/** installs rounding locks for the given variable in the given knapsack constraint */
    519static
    521 SCIP* scip, /**< SCIP data structure */
    522 SCIP_CONS* cons, /**< knapsack constraint */
    523 SCIP_VAR* var /**< variable of constraint entry */
    524 )
    525{
    526 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
    527
    528 return SCIP_OKAY;
    529}
    530
    531/** removes rounding locks for the given variable in the given knapsack constraint */
    532static
    534 SCIP* scip, /**< SCIP data structure */
    535 SCIP_CONS* cons, /**< knapsack constraint */
    536 SCIP_VAR* var /**< variable of constraint entry */
    537 )
    538{
    539 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
    540
    541 return SCIP_OKAY;
    542}
    543
    544/** catches bound change events for variables in knapsack */
    545static
    547 SCIP* scip, /**< SCIP data structure */
    548 SCIP_CONS* cons, /**< constraint */
    549 SCIP_CONSDATA* consdata, /**< constraint data */
    550 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    551 )
    552{
    553 int i;
    554
    555 assert(cons != NULL);
    556 assert(consdata != NULL);
    557 assert(consdata->nvars == 0 || consdata->vars != NULL);
    558 assert(consdata->nvars == 0 || consdata->weights != NULL);
    559 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
    560
    561 for( i = 0; i < consdata->nvars; i++)
    562 {
    563 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
    565 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
    566 }
    567
    568 return SCIP_OKAY;
    569}
    570
    571/** drops bound change events for variables in knapsack */
    572static
    574 SCIP* scip, /**< SCIP data structure */
    575 SCIP_CONSDATA* consdata, /**< constraint data */
    576 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    577 )
    578{
    579 int i;
    580
    581 assert(consdata != NULL);
    582 assert(consdata->nvars == 0 || consdata->vars != NULL);
    583 assert(consdata->nvars == 0 || consdata->weights != NULL);
    584 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
    585
    586 for( i = 0; i < consdata->nvars; i++)
    587 {
    589 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
    590 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
    591 }
    592
    593 return SCIP_OKAY;
    594}
    595
    596/** ensures, that vars and vals arrays can store at least num entries */
    597static
    599 SCIP* scip, /**< SCIP data structure */
    600 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
    601 int num, /**< minimum number of entries to store */
    602 SCIP_Bool transformed /**< is constraint from transformed problem? */
    603 )
    604{
    605 assert(consdata != NULL);
    606 assert(consdata->nvars <= consdata->varssize);
    607
    608 if( num > consdata->varssize )
    609 {
    610 int newsize;
    611
    612 newsize = SCIPcalcMemGrowSize(scip, num);
    613 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
    614 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
    615 if( transformed )
    616 {
    617 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
    618 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
    619 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
    620 }
    621 else
    622 {
    623 assert(consdata->eventdata == NULL);
    624 assert(consdata->cliquepartition == NULL);
    625 assert(consdata->negcliquepartition == NULL);
    626 }
    627 consdata->varssize = newsize;
    628 }
    629 assert(num <= consdata->varssize);
    630
    631 return SCIP_OKAY;
    632}
    633
    634/** updates all weight sums for fixed and unfixed variables */
    635static
    637 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
    638 SCIP_VAR* var, /**< variable for this weight */
    639 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
    640 )
    641{
    642 assert(consdata != NULL);
    643 assert(var != NULL);
    644
    645 consdata->weightsum += weightdelta;
    646
    647 if( SCIPvarGetLbLocal(var) > 0.5 )
    648 consdata->onesweightsum += weightdelta;
    649
    650 assert(consdata->weightsum >= 0);
    651 assert(consdata->onesweightsum >= 0);
    652}
    653
    654/** creates knapsack constraint data */
    655static
    657 SCIP* scip, /**< SCIP data structure */
    658 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
    659 int nvars, /**< number of variables in knapsack */
    660 SCIP_VAR** vars, /**< variables of knapsack */
    661 SCIP_Longint* weights, /**< weights of knapsack items */
    662 SCIP_Longint capacity /**< capacity of knapsack */
    663 )
    664{
    665 int v;
    666 SCIP_Longint constant;
    667
    668 assert(consdata != NULL);
    669
    670 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
    671
    672 constant = 0L;
    673 (*consdata)->vars = NULL;
    674 (*consdata)->weights = NULL;
    675 (*consdata)->nvars = 0;
    676 if( nvars > 0 )
    677 {
    678 SCIP_VAR** varsbuffer;
    679 SCIP_Longint* weightsbuffer;
    680 int k;
    681
    682 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
    683 SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
    684
    685 k = 0;
    686 for( v = 0; v < nvars; ++v )
    687 {
    688 assert(vars[v] != NULL);
    689 assert(SCIPvarIsBinary(vars[v]));
    690
    691 /* all weight have to be non negative */
    692 assert( weights[v] >= 0 );
    693
    694 if( weights[v] > 0 )
    695 {
    696 /* treat fixed variables as constants if problem compression is enabled */
    698 {
    699 /* only if the variable is fixed to 1, we add its weight to the constant */
    700 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
    701 constant += weights[v];
    702 }
    703 else
    704 {
    705 varsbuffer[k] = vars[v];
    706 weightsbuffer[k] = weights[v];
    707 ++k;
    708 }
    709 }
    710 }
    711 assert(k >= 0);
    712 assert(constant >= 0);
    713
    714 (*consdata)->nvars = k;
    715
    716 /* copy the active variables and weights into the constraint data structure */
    717 if( k > 0 )
    718 {
    719 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
    720 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
    721 }
    722
    723 /* free buffer storage */
    724 SCIPfreeBufferArray(scip, &weightsbuffer);
    725 SCIPfreeBufferArray(scip, &varsbuffer);
    726 }
    727
    728 (*consdata)->varssize = (*consdata)->nvars;
    729 (*consdata)->capacity = capacity - constant;
    730 (*consdata)->eventdata = NULL;
    731 (*consdata)->cliquepartition = NULL;
    732 (*consdata)->negcliquepartition = NULL;
    733 (*consdata)->row = NULL;
    734 (*consdata)->nlrow = NULL;
    735 (*consdata)->weightsum = 0;
    736 (*consdata)->onesweightsum = 0;
    737 (*consdata)->ncliques = 0;
    738 (*consdata)->nnegcliques = 0;
    739 (*consdata)->presolvedtiming = 0;
    740 (*consdata)->sorted = FALSE;
    741 (*consdata)->cliquepartitioned = FALSE;
    742 (*consdata)->negcliquepartitioned = FALSE;
    743 (*consdata)->ncliqueslastpart = -1;
    744 (*consdata)->ncliqueslastnegpart = -1;
    745 (*consdata)->merged = FALSE;
    746 (*consdata)->cliquesadded = FALSE;
    747 (*consdata)->varsdeleted = FALSE;
    748 (*consdata)->existmultaggr = FALSE;
    749
    750 /* get transformed variables, if we are in the transformed problem */
    752 {
    753 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
    754
    755 for( v = 0; v < (*consdata)->nvars; v++ )
    756 {
    757 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
    758 assert(var != NULL);
    759 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
    760 }
    761
    762 /* allocate memory for additional data structures */
    763 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
    764 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
    765 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
    766 }
    767
    768 /* calculate sum of weights and capture variables */
    769 for( v = 0; v < (*consdata)->nvars; ++v )
    770 {
    771 /* calculate sum of weights */
    772 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
    773
    774 /* capture variables */
    775 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
    776 }
    777 return SCIP_OKAY;
    778}
    779
    780/** frees knapsack constraint data */
    781static
    783 SCIP* scip, /**< SCIP data structure */
    784 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
    785 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    786 )
    787{
    788 assert(consdata != NULL);
    789 assert(*consdata != NULL);
    790
    791 if( (*consdata)->row != NULL )
    792 {
    793 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
    794 }
    795 if( (*consdata)->nlrow != NULL )
    796 {
    797 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
    798 }
    799 if( (*consdata)->eventdata != NULL )
    800 {
    801 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
    802 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
    803 }
    804 if( (*consdata)->negcliquepartition != NULL )
    805 {
    806 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
    807 }
    808 if( (*consdata)->cliquepartition != NULL )
    809 {
    810 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
    811 }
    812 if( (*consdata)->vars != NULL )
    813 {
    814 int v;
    815
    816 /* release variables */
    817 for( v = 0; v < (*consdata)->nvars; v++ )
    818 {
    819 assert((*consdata)->vars[v] != NULL);
    820 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
    821 }
    822
    823 assert( (*consdata)->weights != NULL );
    824 assert( (*consdata)->varssize > 0 );
    825 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
    826 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
    827 }
    828
    829 SCIPfreeBlockMemory(scip, consdata);
    830
    831 return SCIP_OKAY;
    832}
    833
    834/** changes a single weight in knapsack constraint data */
    835static
    837 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
    838 int item, /**< item number */
    839 SCIP_Longint newweight /**< new weight of item */
    840 )
    841{
    842 SCIP_Longint oldweight;
    843 SCIP_Longint weightdiff;
    844
    845 assert(consdata != NULL);
    846 assert(0 <= item && item < consdata->nvars);
    847
    848 oldweight = consdata->weights[item];
    849 weightdiff = newweight - oldweight;
    850 consdata->weights[item] = newweight;
    851
    852 /* update weight sums for all and fixed variables */
    853 updateWeightSums(consdata, consdata->vars[item], weightdiff);
    854
    855 if( consdata->eventdata != NULL )
    856 {
    857 assert(consdata->eventdata[item] != NULL);
    858 assert(consdata->eventdata[item]->weight == oldweight);
    859 consdata->eventdata[item]->weight = newweight;
    860 }
    861
    862 consdata->presolvedtiming = 0;
    863 consdata->sorted = FALSE;
    864
    865 /* recalculate cliques extraction after a weight was increased */
    866 if( oldweight < newweight )
    867 {
    868 consdata->cliquesadded = FALSE;
    869 }
    870}
    871
    872/** creates LP row corresponding to knapsack constraint */
    873static
    875 SCIP* scip, /**< SCIP data structure */
    876 SCIP_CONS* cons /**< knapsack constraint */
    877 )
    878{
    879 SCIP_CONSDATA* consdata;
    880 int i;
    881
    882 consdata = SCIPconsGetData(cons);
    883 assert(consdata != NULL);
    884 assert(consdata->row == NULL);
    885
    886 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
    887 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
    889
    890 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
    891 for( i = 0; i < consdata->nvars; ++i )
    892 {
    893 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
    894 }
    895 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
    896
    897 return SCIP_OKAY;
    898}
    899
    900/** adds linear relaxation of knapsack constraint to the LP */
    901static
    903 SCIP* scip, /**< SCIP data structure */
    904 SCIP_CONS* cons, /**< knapsack constraint */
    905 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
    906 )
    907{
    908 SCIP_CONSDATA* consdata;
    909
    910 assert( cutoff != NULL );
    911 *cutoff = FALSE;
    912
    913 consdata = SCIPconsGetData(cons);
    914 assert(consdata != NULL);
    915
    916 if( consdata->row == NULL )
    917 {
    919 }
    920 assert(consdata->row != NULL);
    921
    922 /* insert LP row as cut */
    923 if( !SCIProwIsInLP(consdata->row) )
    924 {
    925 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
    926 SCIPconsGetName(cons), consdata->capacity);
    927 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, consdata->row, NULL) ) );
    928 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
    929 }
    930
    931 return SCIP_OKAY;
    932}
    933
    934/** adds knapsack constraint as row to the NLP, if not added yet */
    935static
    937 SCIP* scip, /**< SCIP data structure */
    938 SCIP_CONS* cons /**< knapsack constraint */
    939 )
    940{
    941 SCIP_CONSDATA* consdata;
    942
    943 assert(SCIPisNLPConstructed(scip));
    944
    945 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
    946 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
    947 return SCIP_OKAY;
    948
    949 consdata = SCIPconsGetData(cons);
    950 assert(consdata != NULL);
    951
    952 if( consdata->nlrow == NULL )
    953 {
    954 SCIP_Real* coefs;
    955 int i;
    956
    957 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
    958 for( i = 0; i < consdata->nvars; ++i )
    959 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
    960
    961 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
    962 consdata->nvars, consdata->vars, coefs, NULL,
    963 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
    964
    965 assert(consdata->nlrow != NULL);
    966
    967 SCIPfreeBufferArray(scip, &coefs);
    968 }
    969
    970 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
    971 {
    972 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
    973 }
    974
    975 return SCIP_OKAY;
    976}
    977
    978/** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
    979static
    981 SCIP* scip, /**< SCIP data structure */
    982 SCIP_CONS* cons, /**< constraint to check */
    983 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
    984 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
    985 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
    986 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
    987 )
    988{
    989 SCIP_CONSDATA* consdata;
    990
    991 assert(violated != NULL);
    992
    993 consdata = SCIPconsGetData(cons);
    994 assert(consdata != NULL);
    995
    996 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
    997 SCIPconsGetName(cons), (void*)sol, checklprows);
    998
    999 *violated = FALSE;
    1000
    1001 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
    1002 {
    1003 SCIP_Real normsum = 0.0;
    1004 SCIP_Real hugesum = 0.0;
    1005 SCIP_Real absviol;
    1006 SCIP_Real relviol;
    1007 int v;
    1008
    1009 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
    1010 * enforcement
    1011 */
    1012 if( sol == NULL )
    1013 {
    1014 SCIP_CALL( SCIPincConsAge(scip, cons) );
    1015 }
    1016
    1017 /* sum separately over normal and huge weight contributions in order to reduce numerical cancellation */
    1018 for( v = consdata->nvars - 1; v >= 0; --v )
    1019 {
    1020 assert(SCIPvarIsBinary(consdata->vars[v]));
    1021
    1022 if( SCIPisHugeValue(scip, (SCIP_Real)consdata->weights[v]) )
    1023 hugesum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
    1024 else
    1025 normsum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
    1026 }
    1027
    1028 /* calculate constraint violation and update it in solution */
    1029 normsum += hugesum;
    1030
    1031 if( normsum > consdata->capacity )
    1032 {
    1033 absviol = normsum - consdata->capacity;
    1034 relviol = SCIPrelDiff(normsum, (SCIP_Real)consdata->capacity);
    1035 }
    1036 else
    1037 {
    1038 absviol = 0.0;
    1039 relviol = 0.0;
    1040 }
    1041
    1042 if( sol != NULL )
    1043 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
    1044
    1045 if( SCIPisFeasPositive(scip, absviol) )
    1046 {
    1047 *violated = TRUE;
    1048
    1049 /* only reset constraint age if we are in enforcement */
    1050 if( sol == NULL )
    1051 {
    1053 }
    1054
    1055 if( printreason )
    1056 {
    1057 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    1058
    1059 SCIPinfoMessage(scip, NULL, ";\n");
    1060 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
    1061 }
    1062 }
    1063 }
    1064
    1065 return SCIP_OKAY;
    1066}
    1067
    1068/* IDX computes the integer index for the optimal solution array */
    1069#define IDX(j,d) ((j)*(intcap)+(d))
    1070
    1071/** solves knapsack problem in maximization form exactly using dynamic programming;
    1072 * if needed, one can provide arrays to store all selected items and all not selected items
    1073 *
    1074 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
    1075 *
    1076 * @note the algorithm will first compute a greedy solution and terminate
    1077 * if the greedy solution is proven to be optimal.
    1078 * The dynamic programming algorithm runs with a time and space complexity
    1079 * of O(nitems * capacity).
    1080 *
    1081 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
    1082 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
    1083 * to be checked whether they are faster and whether they can reconstruct the solution.
    1084 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
    1085 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
    1086 * This could be implemented, however, it would be technically a bit cumbersome,
    1087 * since one needs the greedy solution and the LP-value for this.
    1088 * This is currently only available after the redundant items have already been sorted out.
    1089 */
    1091 SCIP* scip, /**< SCIP data structure */
    1092 int nitems, /**< number of available items */
    1093 SCIP_Longint* weights, /**< item weights */
    1094 SCIP_Real* profits, /**< item profits */
    1095 SCIP_Longint capacity, /**< capacity of knapsack */
    1096 int* items, /**< item numbers */
    1097 int* solitems, /**< array to store items in solution, or NULL */
    1098 int* nonsolitems, /**< array to store items not in solution, or NULL */
    1099 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
    1100 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
    1101 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
    1102 SCIP_Bool* success /**< pointer to store if an error occurred during solving
    1103 * (normally a memory problem) */
    1104 )
    1105{
    1106 SCIP_RETCODE retcode;
    1107 SCIP_Real* tempsort;
    1108 SCIP_Real* optvalues;
    1109 int intcap;
    1110 int d;
    1111 int j;
    1112 int greedymedianpos;
    1113 SCIP_Longint weightsum;
    1114 int* myitems;
    1115 SCIP_Longint* myweights;
    1116 SCIP_Real* realweights;
    1117 int* allcurrminweight;
    1118 SCIP_Real* myprofits;
    1119 int nmyitems;
    1120 SCIP_Longint gcd;
    1121 SCIP_Longint minweight;
    1122 SCIP_Longint maxweight;
    1123 int currminweight;
    1124 SCIP_Longint greedysolweight;
    1125 SCIP_Real greedysolvalue;
    1126 SCIP_Real greedyupperbound;
    1127 SCIP_Bool eqweights;
    1128 SCIP_Bool intprofits;
    1129
    1130 assert(weights != NULL);
    1131 assert(profits != NULL);
    1132 assert(capacity >= 0);
    1133 assert(items != NULL);
    1134 assert(nitems >= 0);
    1135 assert(success != NULL);
    1136
    1137 *success = TRUE;
    1138
    1139#ifndef NDEBUG
    1140 for( j = nitems - 1; j >= 0; --j )
    1141 assert(weights[j] >= 0);
    1142#endif
    1143
    1144 SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
    1145
    1146 /* initializing solution value */
    1147 if( solval != NULL )
    1148 *solval = 0.0;
    1149
    1150 /* init solution information */
    1151 if( solitems != NULL )
    1152 {
    1153 assert(items != NULL);
    1154 assert(nsolitems != NULL);
    1155 assert(nonsolitems != NULL);
    1156 assert(nnonsolitems != NULL);
    1157
    1158 *nnonsolitems = 0;
    1159 *nsolitems = 0;
    1160 }
    1161
    1162 /* allocate temporary memory */
    1163 SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
    1164 SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
    1165 SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
    1166 nmyitems = 0;
    1167 weightsum = 0;
    1168 minweight = SCIP_LONGINT_MAX;
    1169 maxweight = 0;
    1170
    1171 /* remove unnecessary items */
    1172 for( j = 0; j < nitems; ++j )
    1173 {
    1174 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
    1175
    1176 /* item does not fit */
    1177 if( weights[j] > capacity )
    1178 {
    1179 if( solitems != NULL )
    1180 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
    1181 }
    1182 /* item is not profitable */
    1183 else if( profits[j] <= 0.0 )
    1184 {
    1185 if( solitems != NULL )
    1186 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
    1187 }
    1188 /* item always fits */
    1189 else if( weights[j] == 0 )
    1190 {
    1191 if( solitems != NULL )
    1192 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
    1193
    1194 if( solval != NULL )
    1195 *solval += profits[j];
    1196 }
    1197 /* all important items */
    1198 else
    1199 {
    1200 myweights[nmyitems] = weights[j];
    1201 myprofits[nmyitems] = profits[j];
    1202 myitems[nmyitems] = items[j];
    1203
    1204 /* remember smallest item */
    1205 if( myweights[nmyitems] < minweight )
    1206 minweight = myweights[nmyitems];
    1207
    1208 /* remember bigest item */
    1209 if( myweights[nmyitems] > maxweight )
    1210 maxweight = myweights[nmyitems];
    1211
    1212 weightsum += myweights[nmyitems];
    1213 ++nmyitems;
    1214 }
    1215 }
    1216
    1217 intprofits = TRUE;
    1218 /* check if all profits are integer to strengthen the upper bound on the greedy solution */
    1219 for( j = 0; j < nmyitems && intprofits; ++j )
    1220 intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
    1221
    1222 /* if no item is left then goto end */
    1223 if( nmyitems == 0 )
    1224 {
    1225 SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
    1226
    1227 goto TERMINATE;
    1228 }
    1229
    1230 /* if all items fit, we also do not need to do the expensive stuff later on */
    1231 if( weightsum > 0 && weightsum <= capacity )
    1232 {
    1233 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
    1234
    1235 for( j = nmyitems - 1; j >= 0; --j )
    1236 {
    1237 if( solitems != NULL )
    1238 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
    1239
    1240 if( solval != NULL )
    1241 *solval += myprofits[j];
    1242 }
    1243
    1244 goto TERMINATE;
    1245 }
    1246
    1247 assert(0 < minweight && minweight <= capacity );
    1248 assert(0 < maxweight && maxweight <= capacity);
    1249
    1250 /* make weights relatively prime */
    1251 eqweights = TRUE;
    1252 if( maxweight > 1 )
    1253 {
    1254 /* determine greatest common divisor */
    1255 gcd = myweights[nmyitems - 1];
    1256 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
    1257 gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
    1258
    1259 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
    1260
    1261 /* divide by greatest common divisor */
    1262 if( gcd > 1 )
    1263 {
    1264 for( j = nmyitems - 1; j >= 0; --j )
    1265 {
    1266 myweights[j] /= gcd;
    1267 eqweights = eqweights && (myweights[j] == 1);
    1268 }
    1269 capacity /= gcd;
    1270 minweight /= gcd;
    1271 }
    1272 else
    1273 eqweights = FALSE;
    1274 }
    1275 assert(minweight <= capacity);
    1276
    1277 /* if only one item fits, then take the best */
    1278 if( minweight > capacity / 2 )
    1279 {
    1280 int p;
    1281
    1282 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
    1283
    1284 p = nmyitems - 1;
    1285
    1286 /* find best item */
    1287 for( j = nmyitems - 2; j >= 0; --j )
    1288 {
    1289 if( myprofits[j] > myprofits[p] )
    1290 p = j;
    1291 }
    1292
    1293 /* update solution information */
    1294 if( solitems != NULL )
    1295 {
    1296 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
    1297
    1298 solitems[(*nsolitems)++] = myitems[p];
    1299 for( j = nmyitems - 1; j >= 0; --j )
    1300 {
    1301 if( j != p )
    1302 nonsolitems[(*nnonsolitems)++] = myitems[j];
    1303 }
    1304 }
    1305 /* update solution value */
    1306 if( solval != NULL )
    1307 *solval += myprofits[p];
    1308
    1309 goto TERMINATE;
    1310 }
    1311
    1312 /* if all items have the same weight, then take the best */
    1313 if( eqweights )
    1314 {
    1315 SCIP_Real addval = 0.0;
    1316
    1317 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
    1318
    1319 SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
    1320
    1321 /* update solution information */
    1322 if( solitems != NULL || solval != NULL )
    1323 {
    1324 SCIP_Longint i;
    1325
    1326 /* if all items would fit we had handled this case before */
    1327 assert((SCIP_Longint) nmyitems > capacity);
    1328 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
    1329
    1330 /* take the first best items into the solution */
    1331 for( i = capacity - 1; i >= 0; --i )
    1332 {
    1333 if( solitems != NULL )
    1334 solitems[(*nsolitems)++] = myitems[i];
    1335 addval += myprofits[i];
    1336 }
    1337
    1338 if( solitems != NULL )
    1339 {
    1340 /* the rest are not in the solution */
    1341 for( i = nmyitems - 1; i >= capacity; --i )
    1342 nonsolitems[(*nnonsolitems)++] = myitems[i];
    1343 }
    1344 }
    1345 /* update solution value */
    1346 if( solval != NULL )
    1347 {
    1348 assert(addval > 0.0);
    1349 *solval += addval;
    1350 }
    1351
    1352 goto TERMINATE;
    1353 }
    1354
    1355 SCIPdebugMsg(scip, "Determine greedy solution.\n");
    1356
    1357 /* sort myitems (plus corresponding arrays myweights and myprofits) such that
    1358 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
    1359 */
    1360 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
    1361 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
    1362
    1363 for( j = 0; j < nmyitems; ++j )
    1364 {
    1365 tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
    1366 realweights[j] = (SCIP_Real)myweights[j];
    1367 }
    1368
    1369 SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
    1370 (SCIP_Real)capacity, nmyitems, &greedymedianpos);
    1371
    1372 SCIPfreeBufferArray(scip, &realweights);
    1373 SCIPfreeBufferArray(scip, &tempsort);
    1374
    1375 /* initialize values for greedy solution information */
    1376 greedysolweight = 0;
    1377 greedysolvalue = 0.0;
    1378
    1379 /* determine greedy solution */
    1380 for( j = 0; j < greedymedianpos; ++j )
    1381 {
    1382 assert(myweights[j] <= capacity);
    1383
    1384 /* update greedy solution weight and value */
    1385 greedysolweight += myweights[j];
    1386 greedysolvalue += myprofits[j];
    1387 }
    1388
    1389 assert(0 < greedysolweight && greedysolweight <= capacity);
    1390 assert(greedysolvalue > 0.0);
    1391
    1392 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
    1393 * - the greedy solution reaches the capacity, because then the LP solution is integral;
    1394 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
    1395 greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
    1396 if( intprofits )
    1397 greedyupperbound = SCIPfloor(scip, greedyupperbound);
    1398 if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
    1399 {
    1400 SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
    1401
    1402 /* update solution information */
    1403 if( solitems != NULL )
    1404 {
    1405 int l;
    1406
    1407 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
    1408
    1409 /* collect items */
    1410 for( l = 0; l < j; ++l )
    1411 solitems[(*nsolitems)++] = myitems[l];
    1412 for ( ; l < nmyitems; ++l )
    1413 nonsolitems[(*nnonsolitems)++] = myitems[l];
    1414 }
    1415 /* update solution value */
    1416 if( solval != NULL )
    1417 {
    1418 assert(greedysolvalue > 0.0);
    1419 *solval += greedysolvalue;
    1420 }
    1421
    1422 goto TERMINATE;
    1423 }
    1424
    1425 /* in the following table we do not need the first minweight columns */
    1426 capacity -= (minweight - 1);
    1427
    1428 /* we can only handle integers */
    1429 if( capacity >= INT_MAX )
    1430 {
    1431 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
    1432
    1433 *success = FALSE;
    1434 goto TERMINATE;
    1435 }
    1436 assert(capacity < INT_MAX);
    1437
    1438 intcap = (int)capacity;
    1439 assert(intcap >= 0);
    1440 assert(nmyitems > 0);
    1441 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
    1442
    1443 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
    1444 * computing the size for the allocation
    1445 */
    1446 if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (SIZE_MAX / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
    1447 {
    1448 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
    1449
    1450 *success = FALSE;
    1451 goto TERMINATE;
    1452 }
    1453
    1454 /* allocate temporary memory and check for memory exceedance */
    1455 retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
    1456 if( retcode == SCIP_NOMEMORY )
    1457 {
    1458 SCIPdebugMsg(scip, "Did not get enough memory.\n");
    1459
    1460 *success = FALSE;
    1461 goto TERMINATE;
    1462 }
    1463 else
    1464 {
    1465 SCIP_CALL( retcode );
    1466 }
    1467
    1468 SCIPdebugMsg(scip, "Start real exact algorithm.\n");
    1469
    1470 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
    1471 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
    1472 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
    1473 * 'nmyitem' values
    1474 */
    1475 SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
    1476 assert(myweights[0] - minweight < INT_MAX);
    1477 currminweight = (int) (myweights[0] - minweight);
    1478 allcurrminweight[0] = currminweight;
    1479
    1480 /* fills first row of dynamic programming table with optimal values */
    1481 for( d = currminweight; d < intcap; ++d )
    1482 optvalues[d] = myprofits[0];
    1483
    1484 /* fills dynamic programming table with optimal values */
    1485 for( j = 1; j < nmyitems; ++j )
    1486 {
    1487 int intweight;
    1488
    1489 /* compute important part of weight, which will be represented in the table */
    1490 intweight = (int)(myweights[j] - minweight);
    1491 assert(0 <= intweight && intweight < intcap);
    1492
    1493 /* copy all nonzeros from row above */
    1494 for( d = currminweight; d < intweight && d < intcap; ++d )
    1495 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
    1496
    1497 /* update corresponding row */
    1498 for( d = intweight; d < intcap; ++d )
    1499 {
    1500 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
    1501 if( d < currminweight )
    1502 optvalues[IDX(j,d)] = myprofits[j];
    1503 else
    1504 {
    1505 SCIP_Real sumprofit;
    1506
    1507 if( d - myweights[j] < currminweight )
    1508 sumprofit = myprofits[j];
    1509 else
    1510 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
    1511
    1512 optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
    1513 }
    1514 }
    1515
    1516 /* update currminweight */
    1517 if( intweight < currminweight )
    1518 currminweight = intweight;
    1519
    1520 allcurrminweight[j] = currminweight;
    1521 }
    1522
    1523 /* update optimal solution by following the table */
    1524 if( solitems != NULL )
    1525 {
    1526 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
    1527 d = intcap - 1;
    1528
    1529 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
    1530
    1531 /* insert all items in (non-) solution vector */
    1532 for( j = nmyitems - 1; j > 0; --j )
    1533 {
    1534 /* if the following condition holds this means all remaining items does not fit anymore */
    1535 if( d < allcurrminweight[j] )
    1536 {
    1537 /* we cannot have exceeded our capacity */
    1538 assert((SCIP_Longint) d >= -minweight);
    1539 break;
    1540 }
    1541
    1542 /* collect solution items; the first condition means that no further item can fit anymore, but this does */
    1543 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
    1544 {
    1545 solitems[(*nsolitems)++] = myitems[j];
    1546
    1547 /* check that we do not have an underflow */
    1548 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
    1549 d = (int)(d - myweights[j]);
    1550 }
    1551 /* collect non-solution items */
    1552 else
    1553 nonsolitems[(*nnonsolitems)++] = myitems[j];
    1554 }
    1555
    1556 /* insert remaining items */
    1557 if( d >= allcurrminweight[j] )
    1558 {
    1559 assert(j == 0);
    1560 solitems[(*nsolitems)++] = myitems[j];
    1561 }
    1562 else
    1563 {
    1564 assert(j >= 0);
    1565 assert(d < allcurrminweight[j]);
    1566
    1567 for( ; j >= 0; --j )
    1568 nonsolitems[(*nnonsolitems)++] = myitems[j];
    1569 }
    1570
    1571 assert(*nsolitems + *nnonsolitems == nitems);
    1572 }
    1573
    1574 /* update solution value */
    1575 if( solval != NULL )
    1576 *solval += optvalues[IDX(nmyitems-1,intcap-1)];
    1577 SCIPfreeBufferArray(scip, &allcurrminweight);
    1578
    1579 /* free all temporary memory */
    1580 SCIPfreeBufferArray(scip, &optvalues);
    1581
    1582 TERMINATE:
    1583 SCIPfreeBufferArray(scip, &myitems);
    1584 SCIPfreeBufferArray(scip, &myprofits);
    1585 SCIPfreeBufferArray(scip, &myweights);
    1586
    1587 return SCIP_OKAY;
    1588}
    1589
    1590/** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
    1591 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
    1592 * selected items
    1593 */
    1595 SCIP* scip, /**< SCIP data structure */
    1596 int nitems, /**< number of available items */
    1597 SCIP_Longint* weights, /**< item weights */
    1598 SCIP_Real* profits, /**< item profits */
    1599 SCIP_Longint capacity, /**< capacity of knapsack */
    1600 int* items, /**< item numbers */
    1601 int* solitems, /**< array to store items in solution, or NULL */
    1602 int* nonsolitems, /**< array to store items not in solution, or NULL */
    1603 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
    1604 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
    1605 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
    1606 )
    1607{
    1608 SCIP_Real* tempsort;
    1609 SCIP_Longint solitemsweight;
    1610 SCIP_Real* realweights;
    1611 int j;
    1612 int criticalindex;
    1613
    1614 assert(weights != NULL);
    1615 assert(profits != NULL);
    1616 assert(capacity >= 0);
    1617 assert(items != NULL);
    1618 assert(nitems >= 0);
    1619
    1620 if( solitems != NULL )
    1621 {
    1622 *nsolitems = 0;
    1623 *nnonsolitems = 0;
    1624 }
    1625 if( solval != NULL )
    1626 *solval = 0.0;
    1627
    1628 /* initialize data for median search */
    1629 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
    1630 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
    1631 for( j = nitems - 1; j >= 0; --j )
    1632 {
    1633 tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
    1634 realweights[j] = (SCIP_Real)weights[j];
    1635 }
    1636
    1637 /* partially sort indices such that all elements that are larger than the break item appear first */
    1638 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
    1639
    1640 /* selects items as long as they fit into the knapsack */
    1641 solitemsweight = 0;
    1642 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
    1643 {
    1644 if( solitems != NULL )
    1645 solitems[(*nsolitems)++] = items[j];
    1646
    1647 if( solval != NULL )
    1648 (*solval) += profits[j];
    1649 solitemsweight += weights[j];
    1650 }
    1651 if ( solitems != NULL )
    1652 {
    1653 for( ; j < nitems; j++ )
    1654 nonsolitems[(*nnonsolitems)++] = items[j];
    1655 }
    1656
    1657 SCIPfreeBufferArray(scip, &realweights);
    1658 SCIPfreeBufferArray(scip, &tempsort);
    1659
    1660 return SCIP_OKAY;
    1661}
    1662
    1663#ifdef SCIP_DEBUG
    1664/** prints all nontrivial GUB constraints and their LP solution values */
    1665static
    1666void GUBsetPrint(
    1667 SCIP* scip, /**< SCIP data structure */
    1668 SCIP_GUBSET* gubset, /**< GUB set data structure */
    1669 SCIP_VAR** vars, /**< variables in knapsack constraint */
    1670 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
    1671 )
    1672{
    1673 int nnontrivialgubconss;
    1674 int c;
    1675
    1676 nnontrivialgubconss = 0;
    1677
    1678 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
    1679
    1680 /* print out all nontrivial GUB constraints, i.e., with more than one variable */
    1681 for( c = 0; c < gubset->ngubconss; c++ )
    1682 {
    1683 SCIP_Real gubsolval;
    1684
    1685 assert(gubset->gubconss[c]->ngubvars >= 0);
    1686
    1687 /* nontrivial GUB */
    1688 if( gubset->gubconss[c]->ngubvars > 1 )
    1689 {
    1690 int v;
    1691
    1692 gubsolval = 0.0;
    1693 SCIPdebugMsg(scip, " GUB<%d>:\n", c);
    1694
    1695 /* print GUB var */
    1696 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
    1697 {
    1698 int currentvar;
    1699
    1700 currentvar = gubset->gubconss[c]->gubvars[v];
    1701 if( solvals != NULL )
    1702 {
    1703 gubsolval += solvals[currentvar];
    1704 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
    1705 }
    1706 else
    1707 {
    1708 SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
    1709 }
    1710 }
    1711
    1712 /* check whether LP solution satisfies the GUB constraint */
    1713 if( solvals != NULL )
    1714 {
    1715 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
    1716 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
    1717 }
    1718 else
    1719 {
    1720 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
    1721 }
    1722 nnontrivialgubconss++;
    1723 }
    1724 }
    1725
    1726 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
    1727}
    1728#endif
    1729
    1730/** creates an empty GUB constraint */
    1731static
    1733 SCIP* scip, /**< SCIP data structure */
    1734 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
    1735 )
    1736{
    1737 assert(scip != NULL);
    1738 assert(gubcons != NULL);
    1739
    1740 /* allocate memory for GUB constraint data structures */
    1741 SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
    1742 (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
    1743 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
    1744 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
    1745
    1746 (*gubcons)->ngubvars = 0;
    1747
    1748 return SCIP_OKAY;
    1749}
    1750
    1751/** frees GUB constraint */
    1752static
    1754 SCIP* scip, /**< SCIP data structure */
    1755 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
    1756 )
    1757{
    1758 assert(scip != NULL);
    1759 assert(gubcons != NULL);
    1760 assert((*gubcons)->gubvars != NULL);
    1761 assert((*gubcons)->gubvarsstatus != NULL);
    1762
    1763 /* free allocated memory */
    1764 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
    1765 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
    1766 SCIPfreeBuffer(scip, gubcons);
    1767}
    1768
    1769/** adds variable to given GUB constraint */
    1770static
    1772 SCIP* scip, /**< SCIP data structure */
    1773 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
    1774 int var /**< index of given variable in knapsack constraint */
    1775 )
    1776{
    1777 assert(scip != NULL);
    1778 assert(gubcons != NULL);
    1779 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
    1780 assert(gubcons->gubvars != NULL);
    1781 assert(gubcons->gubvarsstatus != NULL);
    1782 assert(var >= 0);
    1783
    1784 /* add variable to GUB constraint */
    1785 gubcons->gubvars[gubcons->ngubvars] = var;
    1786 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
    1787 gubcons->ngubvars++;
    1788
    1789 /* increase space allocated to GUB constraint if the number of variables reaches the size */
    1790 if( gubcons->ngubvars == gubcons->gubvarssize )
    1791 {
    1792 int newlen;
    1793
    1794 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
    1795 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
    1796 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
    1797
    1798 gubcons->gubvarssize = newlen;
    1799 }
    1800
    1801 return SCIP_OKAY;
    1802}
    1803
    1804/** deletes variable from its current GUB constraint */
    1805static
    1807 SCIP* scip, /**< SCIP data structure */
    1808 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
    1809 int var, /**< index of given variable in knapsack constraint */
    1810 int gubvarsidx /**< index of the variable in its current GUB constraint */
    1811 )
    1812{
    1813 assert(scip != NULL);
    1814 assert(gubcons != NULL);
    1815 assert(var >= 0);
    1816 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
    1817 assert(gubcons->ngubvars >= gubvarsidx+1);
    1818 assert(gubcons->gubvars[gubvarsidx] == var);
    1819
    1820 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
    1821 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
    1822 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
    1823 gubcons->ngubvars--;
    1824
    1825 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
    1826 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
    1827 {
    1828 int newlen;
    1829
    1830 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
    1831
    1832 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
    1833 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
    1834
    1835 gubcons->gubvarssize = newlen;
    1836 }
    1837
    1838 return SCIP_OKAY;
    1839}
    1840
    1841/** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
    1842static
    1844 SCIP* scip, /**< SCIP data structure */
    1845 SCIP_GUBSET* gubset, /**< GUB set data structure */
    1846 SCIP_VAR** vars, /**< variables in knapsack constraint */
    1847 int var, /**< index of given variable in knapsack constraint */
    1848 int oldgubcons, /**< index of old GUB constraint of given variable */
    1849 int newgubcons /**< index of new GUB constraint of given variable */
    1850 )
    1851{
    1852 int oldgubvaridx;
    1853 int replacevar;
    1854 int j;
    1855
    1856 assert(scip != NULL);
    1857 assert(gubset != NULL);
    1858 assert(var >= 0);
    1859 assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
    1860 assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
    1861 assert(oldgubcons != newgubcons);
    1862 assert(gubset->gubconssidx[var] == oldgubcons);
    1863 assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
    1864 assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
    1865
    1866 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
    1867
    1868 oldgubvaridx = gubset->gubvarsidx[var];
    1869
    1870 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
    1871 SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
    1872
    1873 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
    1874 * replacement variable is given by old position of the deleted variable
    1875 */
    1876 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
    1877 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
    1878 gubset->gubvarsidx[replacevar] = oldgubvaridx;
    1879
    1880 /* add variable to the end of new GUB constraint */
    1881 SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
    1882 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
    1883
    1884 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
    1885 gubset->gubconssidx[var] = newgubcons;
    1886 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
    1887
    1888 /* delete old GUB constraint if it became empty */
    1889 if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
    1890 {
    1891 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
    1892#ifdef SCIP_DEBUG
    1893 GUBsetPrint(scip, gubset, vars, NULL);
    1894#endif
    1895
    1896 /* free old GUB constraint */
    1897 GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
    1898
    1899 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
    1900 if( oldgubcons != gubset->ngubconss-1 )
    1901 {
    1902 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
    1903 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
    1904
    1905 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
    1906 * replacement GUB is given by old position of the deleted GUB
    1907 */
    1908 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
    1909 {
    1910 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
    1911 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
    1912 }
    1913 }
    1914
    1915 /* update number of GUB constraints */
    1916 gubset->ngubconss--;
    1917
    1918 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
    1919 * (because it was at the end of the GUB constraint array)
    1920 */
    1921 assert(gubset->gubconssidx[var] == newgubcons
    1922 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
    1923 }
    1924#ifndef NDEBUG
    1925 else
    1926 assert(gubset->gubconssidx[var] == newgubcons);
    1927#endif
    1928
    1929 return SCIP_OKAY;
    1930}
    1931
    1932/** swaps two variables in the same GUB constraint */
    1933static
    1935 SCIP* scip, /**< SCIP data structure */
    1936 SCIP_GUBSET* gubset, /**< GUB set data structure */
    1937 int var1, /**< first variable to be swapped */
    1938 int var2 /**< second variable to be swapped */
    1939 )
    1940{
    1941 int gubcons;
    1942 int var1idx;
    1943 GUBVARSTATUS var1status;
    1944 int var2idx;
    1945 GUBVARSTATUS var2status;
    1946
    1947 assert(scip != NULL);
    1948 assert(gubset != NULL);
    1949
    1950 gubcons = gubset->gubconssidx[var1];
    1951 assert(gubcons == gubset->gubconssidx[var2]);
    1952
    1953 /* nothing to be done if both variables are the same */
    1954 if( var1 == var2 )
    1955 return;
    1956
    1957 /* swap index and status of variables in GUB constraint */
    1958 var1idx = gubset->gubvarsidx[var1];
    1959 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
    1960 var2idx = gubset->gubvarsidx[var2];
    1961 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
    1962
    1963 gubset->gubvarsidx[var1] = var2idx;
    1964 gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
    1965 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
    1966
    1967 gubset->gubvarsidx[var2] = var1idx;
    1968 gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
    1969 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
    1970}
    1971
    1972/** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
    1973static
    1975 SCIP* scip, /**< SCIP data structure */
    1976 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
    1977 int nvars, /**< number of variables in the knapsack constraint */
    1978 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    1979 SCIP_Longint capacity /**< capacity of knapsack */
    1980 )
    1981{
    1982 int i;
    1983
    1984 assert(scip != NULL);
    1985 assert(gubset != NULL);
    1986 assert(nvars > 0);
    1987 assert(weights != NULL);
    1988 assert(capacity >= 0);
    1989
    1990 /* allocate memory for GUB set data structures */
    1991 SCIP_CALL( SCIPallocBuffer(scip, gubset) );
    1992 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
    1993 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
    1994 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
    1995 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
    1996 (*gubset)->ngubconss = nvars;
    1997 (*gubset)->nvars = nvars;
    1998
    1999 /* initialize the set of GUB constraints */
    2000 for( i = 0; i < nvars; i++ )
    2001 {
    2002 /* assign each variable to a new (trivial) GUB constraint */
    2003 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
    2004 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
    2005
    2006 /* set status of GUB constraint to initial */
    2007 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
    2008
    2009 (*gubset)->gubconssidx[i] = i;
    2010 (*gubset)->gubvarsidx[i] = 0;
    2011 assert((*gubset)->gubconss[i]->ngubvars == 1);
    2012
    2013 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
    2014 if( weights[i] > capacity )
    2015 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
    2016 }
    2017
    2018 return SCIP_OKAY;
    2019}
    2020
    2021/** frees GUB set data structure */
    2022static
    2024 SCIP* scip, /**< SCIP data structure */
    2025 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
    2026 )
    2027{
    2028 int i;
    2029
    2030 assert(scip != NULL);
    2031 assert(gubset != NULL);
    2032 assert((*gubset)->gubconss != NULL);
    2033 assert((*gubset)->gubconsstatus != NULL);
    2034 assert((*gubset)->gubconssidx != NULL);
    2035 assert((*gubset)->gubvarsidx != NULL);
    2036
    2037 /* free all GUB constraints */
    2038 for( i = (*gubset)->ngubconss-1; i >= 0; --i )
    2039 {
    2040 assert((*gubset)->gubconss[i] != NULL);
    2041 GUBconsFree(scip, &(*gubset)->gubconss[i]);
    2042 }
    2043
    2044 /* free allocated memory */
    2045 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
    2046 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
    2047 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
    2048 SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
    2049 SCIPfreeBuffer(scip, gubset);
    2050}
    2051
    2052#ifndef NDEBUG
    2053/** checks whether GUB set data structure is consistent */
    2054static
    2056 SCIP* scip, /**< SCIP data structure */
    2057 SCIP_GUBSET* gubset, /**< GUB set data structure */
    2058 SCIP_VAR** vars /**< variables in the knapsack constraint */
    2059 )
    2060{
    2061 int i;
    2062 int gubconsidx;
    2063 int gubvaridx;
    2064 SCIP_VAR* var1;
    2065 SCIP_VAR* var2;
    2066 SCIP_Bool var1negated;
    2067 SCIP_Bool var2negated;
    2068
    2069 assert(scip != NULL);
    2070 assert(gubset != NULL);
    2071
    2072 SCIPdebugMsg(scip, " GUB set consistency check:\n");
    2073
    2074 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
    2075 for( i = 0; i < gubset->nvars; i++ )
    2076 {
    2077 gubconsidx = gubset->gubconssidx[i];
    2078 gubvaridx = gubset->gubvarsidx[i];
    2079
    2080 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
    2081 {
    2082 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
    2083 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
    2084 }
    2085 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
    2086 }
    2087
    2088 /* checks for each GUB whether all pairs of its variables have a common clique */
    2089 for( i = 0; i < gubset->ngubconss; i++ )
    2090 {
    2091 int j;
    2092
    2093 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
    2094 {
    2095 int k;
    2096
    2097 /* get corresponding active problem variable */
    2098 var1 = vars[gubset->gubconss[i]->gubvars[j]];
    2099 var1negated = FALSE;
    2100 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
    2101
    2102 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
    2103 {
    2104 /* get corresponding active problem variable */
    2105 var2 = vars[gubset->gubconss[i]->gubvars[k]];
    2106 var2negated = FALSE;
    2107 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
    2108
    2109 if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
    2110 {
    2111 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
    2112 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
    2113 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
    2114 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
    2115 SCIPvarGetName(var1), k,
    2116 SCIPvarGetName(var2));
    2117 }
    2118
    2119 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
    2120 assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
    2121 }
    2122 }
    2123 }
    2124 SCIPdebugMsg(scip, " --> successful\n");
    2125
    2126 return SCIP_OKAY;
    2127}
    2128#endif
    2129
    2130/** calculates a partition of the given set of binary variables into cliques;
    2131 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
    2132 * were assigned to the same clique;
    2133 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
    2134 * the preceding variables was assigned to clique i-1;
    2135 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
    2136 * variable) and for the remaining variables, a partition with a small number of cliques is constructed
    2137 */
    2138
    2139static
    2141 SCIP*const scip, /**< SCIP data structure */
    2142 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
    2143 int const nvars, /**< number of variables in the clique */
    2144 int*const cliquepartition, /**< array of length nvars to store the clique partition */
    2145 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
    2146 SCIP_Real* solvals /**< solution values of all given binary variables */
    2147 )
    2148{
    2149 SCIP_VAR** tmpvars;
    2150 SCIP_VAR** cliquevars;
    2151 SCIP_Bool* cliquevalues;
    2152 SCIP_Bool* tmpvalues;
    2153 int* varseq;
    2154 int* sortkeys;
    2155 int ncliquevars;
    2156 int maxncliquevarscomp;
    2157 int nignorevars;
    2158 int nvarsused;
    2159 int i;
    2160
    2161 assert(scip != NULL);
    2162 assert(nvars == 0 || vars != NULL);
    2163 assert(nvars == 0 || cliquepartition != NULL);
    2164 assert(ncliques != NULL);
    2165
    2166 if( nvars == 0 )
    2167 {
    2168 *ncliques = 0;
    2169 return SCIP_OKAY;
    2170 }
    2171
    2172 /* allocate temporary memory for storing the variables of the current clique */
    2173 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
    2174 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
    2175 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
    2176 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
    2178 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
    2179
    2180 /* initialize the cliquepartition array with -1 */
    2181 /* initialize the tmpvalues array */
    2182 for( i = nvars - 1; i >= 0; --i )
    2183 {
    2184 tmpvalues[i] = TRUE;
    2185 cliquepartition[i] = -1;
    2186 }
    2187
    2188 /* get corresponding active problem variables */
    2189 SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
    2190
    2191 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
    2192 * by nondecreasing number of cliques the variables are in
    2193 */
    2194 nignorevars = 0;
    2195 nvarsused = 0;
    2196 for( i = 0; i < nvars; i++ )
    2197 {
    2198 if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
    2199 {
    2200 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
    2201 varseq[nvars-1-nignorevars] = i;
    2202 nignorevars++;
    2203 }
    2204 else
    2205 {
    2206 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
    2207 varseq[nvarsused] = i;
    2208 sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
    2209 nvarsused++;
    2210 }
    2211 }
    2212 assert(nvarsused + nignorevars == nvars);
    2213
    2214 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
    2215 SCIPsortIntInt(sortkeys, varseq, nvarsused);
    2216
    2217 maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
    2218
    2219 /* calculate the clique partition */
    2220 *ncliques = 0;
    2221 for( i = 0; i < nvars; ++i )
    2222 {
    2223 if( cliquepartition[varseq[i]] == -1 )
    2224 {
    2225 int j;
    2226
    2227 /* variable starts a new clique */
    2228 cliquepartition[varseq[i]] = *ncliques;
    2229 cliquevars[0] = tmpvars[varseq[i]];
    2230 cliquevalues[0] = tmpvalues[varseq[i]];
    2231 ncliquevars = 1;
    2232
    2233 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
    2234 * if the variable has LP value 1 we do not want it to be in nontrivial cliques
    2235 */
    2236 if( i < nvarsused && SCIPvarIsActive(tmpvars[varseq[i]]) )
    2237 {
    2238 /* greedily fill up the clique */
    2239 for( j = i + 1; j < nvarsused; ++j )
    2240 {
    2241 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
    2242 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
    2243 {
    2244 int k;
    2245
    2246 /* check if every variable in the actual clique is in clique with the new variable */
    2247 for( k = ncliquevars - 1; k >= 0; --k )
    2248 {
    2249 if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
    2250 cliquevalues[k], TRUE) )
    2251 break;
    2252 }
    2253
    2254 if( k == -1 )
    2255 {
    2256 /* put the variable into the same clique */
    2257 cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
    2258 cliquevars[ncliquevars] = tmpvars[varseq[j]];
    2259 cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
    2260 ++ncliquevars;
    2261 }
    2262 }
    2263 }
    2264 }
    2265
    2266 /* this clique is finished */
    2267 ++(*ncliques);
    2268 }
    2269 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
    2270
    2271 /* break if we reached the maximal number of comparisons */
    2272 if( i * nvars > maxncliquevarscomp )
    2273 break;
    2274 }
    2275 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
    2276 for( ; i < nvars; ++i )
    2277 {
    2278 if( cliquepartition[varseq[i]] == -1 )
    2279 {
    2280 cliquepartition[varseq[i]] = *ncliques;
    2281 ++(*ncliques);
    2282 }
    2283 }
    2284
    2285 /* free temporary memory */
    2286 SCIPfreeBufferArray(scip, &sortkeys);
    2287 SCIPfreeBufferArray(scip, &varseq);
    2288 SCIPfreeBufferArray(scip, &tmpvars);
    2289 SCIPfreeBufferArray(scip, &tmpvalues);
    2290 SCIPfreeBufferArray(scip, &cliquevalues);
    2291 SCIPfreeBufferArray(scip, &cliquevars);
    2292
    2293 return SCIP_OKAY;
    2294}
    2295
    2296/** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
    2297static
    2299 SCIP* scip, /**< SCIP data structure */
    2300 SCIP_GUBSET* gubset, /**< GUB set data structure */
    2301 SCIP_VAR** vars, /**< variables in the knapsack constraint */
    2302 SCIP_Real* solvals /**< solution values of all knapsack variables */
    2303 )
    2304{
    2305 int* cliquepartition;
    2306 int* gubfirstvar;
    2307 int ncliques;
    2308 int currentgubconsidx;
    2309 int newgubconsidx;
    2310 int cliqueidx;
    2311 int nvars;
    2312 int i;
    2313
    2314 assert(scip != NULL);
    2315 assert(gubset != NULL);
    2316 assert(vars != NULL);
    2317
    2318 nvars = gubset->nvars;
    2319 assert(nvars >= 0);
    2320
    2321 /* allocate temporary memory for clique partition */
    2322 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
    2323
    2324 /* compute sophisticated clique partition */
    2325 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
    2326
    2327 /* allocate temporary memory for GUB set data structure */
    2328 SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
    2329
    2330 /* translate GUB partition into GUB set data structure */
    2331 for( i = 0; i < ncliques; i++ )
    2332 {
    2333 /* initialize first variable for every GUB */
    2334 gubfirstvar[i] = -1;
    2335 }
    2336 /* move every knapsack variable into GUB defined by clique partition */
    2337 for( i = 0; i < nvars; i++ )
    2338 {
    2339 assert(cliquepartition[i] >= 0);
    2340
    2341 cliqueidx = cliquepartition[i];
    2342 currentgubconsidx = gubset->gubconssidx[i];
    2343 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
    2344
    2345 /* variable is first element in GUB constraint defined by clique partition */
    2346 if( gubfirstvar[cliqueidx] == -1 )
    2347 {
    2348 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
    2349 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
    2350 */
    2351 assert(gubset->gubvarsidx[i] == 0);
    2352 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
    2353
    2354 /* remember the first variable found for the current GUB */
    2355 gubfirstvar[cliqueidx] = i;
    2356 }
    2357 /* variable is additional element of GUB constraint defined by clique partition */
    2358 else
    2359 {
    2360 assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
    2361
    2362 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
    2363 * first variable of this GUB constraint
    2364 */
    2365 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
    2366 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
    2367 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
    2368
    2369 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
    2370 }
    2371 }
    2372
    2373#ifdef SCIP_DEBUG
    2374 /* prints GUB set data structure */
    2375 GUBsetPrint(scip, gubset, vars, solvals);
    2376#endif
    2377
    2378#ifndef NDEBUG
    2379 /* checks consistency of GUB set data structure */
    2380 SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
    2381#endif
    2382
    2383 /* free temporary memory */
    2384 SCIPfreeBufferArray(scip, &gubfirstvar);
    2385 SCIPfreeBufferArray(scip, &cliquepartition);
    2386
    2387 return SCIP_OKAY;
    2388}
    2389
    2390/** gets a most violated cover C (\f$\sum_{j \in C} a_j > a_0\f$) for a given knapsack constraint \f$\sum_{j \in N} a_j x_j \leq a_0\f$
    2391 * taking into consideration the following fixing: \f$j \in C\f$, if \f$j \in N_1 = \{j \in N : x^*_j = 1\}\f$ and
    2392 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
    2393 */
    2394static
    2396 SCIP* scip, /**< SCIP data structure */
    2397 SCIP_VAR** vars, /**< variables in knapsack constraint */
    2398 int nvars, /**< number of variables in knapsack constraint */
    2399 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2400 SCIP_Longint capacity, /**< capacity of knapsack */
    2401 SCIP_Real* solvals, /**< solution values of all problem variables */
    2402 int* covervars, /**< pointer to store cover variables */
    2403 int* noncovervars, /**< pointer to store noncover variables */
    2404 int* ncovervars, /**< pointer to store number of cover variables */
    2405 int* nnoncovervars, /**< pointer to store number of noncover variables */
    2406 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
    2407 SCIP_Bool* found, /**< pointer to store whether a cover was found */
    2408 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
    2409 int* ntightened, /**< pointer to store number of variables with tightened upper bound */
    2410 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
    2411 )
    2412{
    2413 SCIP_Longint* transweights;
    2414 SCIP_Real* transprofits;
    2415 SCIP_Longint transcapacity;
    2416 SCIP_Longint fixedonesweight;
    2417 SCIP_Longint itemsweight;
    2418 SCIP_Bool infeasible;
    2419 int* fixedones;
    2420 int* fixedzeros;
    2421 int* items;
    2422 int nfixedones;
    2423 int nfixedzeros;
    2424 int nitems;
    2425 int j;
    2426
    2427 assert(scip != NULL);
    2428 assert(vars != NULL);
    2429 assert(nvars > 0);
    2430 assert(weights != NULL);
    2431 assert(capacity >= 0);
    2432 assert(solvals != NULL);
    2433 assert(covervars != NULL);
    2434 assert(noncovervars != NULL);
    2435 assert(ncovervars != NULL);
    2436 assert(nnoncovervars != NULL);
    2437 assert(coverweight != NULL);
    2438 assert(found != NULL);
    2439 assert(ntightened != NULL);
    2440 assert(fractional != NULL);
    2441
    2442 SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
    2443
    2444 /* allocates temporary memory */
    2445 SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
    2446 SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
    2447 SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
    2448 SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
    2450
    2451 *found = FALSE;
    2452 *ncovervars = 0;
    2453 *nnoncovervars = 0;
    2454 *coverweight = 0;
    2455 *fractional = TRUE;
    2456
    2457 /* gets the following sets
    2458 * N_1 = {j in N : x*_j = 1} (fixedones),
    2459 * N_0 = {j in N : x*_j = 0} (fixedzeros) and
    2460 * N\‍(N_0 & N_1) (items),
    2461 * where x*_j is the solution value of variable x_j
    2462 */
    2463 nfixedones = 0;
    2464 nfixedzeros = 0;
    2465 nitems = 0;
    2466 fixedonesweight = 0;
    2467 itemsweight = 0;
    2468 *ntightened = 0;
    2469 for( j = 0; j < nvars; j++ )
    2470 {
    2471 assert(SCIPvarIsBinary(vars[j]));
    2472
    2473 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
    2474 if( weights[j] > capacity )
    2475 {
    2476 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
    2477 assert(!infeasible);
    2478 (*ntightened)++;
    2479 continue;
    2480 }
    2481
    2482 /* variable x_j has solution value one */
    2483 if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
    2484 {
    2485 fixedones[nfixedones] = j;
    2486 nfixedones++;
    2487 fixedonesweight += weights[j];
    2488 }
    2489 /* variable x_j has solution value zero */
    2490 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
    2491 {
    2492 fixedzeros[nfixedzeros] = j;
    2493 nfixedzeros++;
    2494 }
    2495 /* variable x_j has fractional solution value */
    2496 else
    2497 {
    2498 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
    2499 items[nitems] = j;
    2500 nitems++;
    2501 itemsweight += weights[j];
    2502 }
    2503 }
    2504 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
    2505
    2506 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
    2507 * the separation routine
    2508 */
    2509 assert(nitems >= 0);
    2510 if( nitems == 0 )
    2511 {
    2512 *fractional = FALSE;
    2513 goto TERMINATE;
    2514 }
    2515 assert(*fractional);
    2516
    2517 /* transforms the traditional separation problem (under consideration of the following fixing:
    2518 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
    2519 *
    2520 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
    2521 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
    2522 * z_j in {0,1}, j in N\‍(N_0 & N_1)
    2523 *
    2524 * to a knapsack problem in maximization form by complementing the variables
    2525 *
    2526 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) -
    2527 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
    2528 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
    2529 * z_j in {0,1}, j in N\‍(N_0 & N_1)
    2530 */
    2531
    2532 /* gets weight and profit of variables in transformed knapsack problem */
    2533 for( j = 0; j < nitems; j++ )
    2534 {
    2535 transweights[j] = weights[items[j]];
    2536 transprofits[j] = 1.0 - solvals[items[j]];
    2537 }
    2538 /* gets capacity of transformed knapsack problem */
    2539 transcapacity = fixedonesweight + itemsweight - capacity - 1;
    2540
    2541 /* if capacity of transformed knapsack problem is less than zero, there is no cover
    2542 * (when variables fixed to zero are not used)
    2543 */
    2544 if( transcapacity < 0 )
    2545 {
    2546 assert(!(*found));
    2547 goto TERMINATE;
    2548 }
    2549
    2550 if( modtransused )
    2551 {
    2552 /* transforms the modified separation problem (under consideration of the following fixing:
    2553 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
    2554 *
    2555 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
    2556 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
    2557 * z_j in {0,1}, j in N\‍(N_0 & N_1)
    2558 *
    2559 * to a knapsack problem in maximization form by complementing the variables
    2560 *
    2561 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j -
    2562 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
    2563 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
    2564 * z_j in {0,1}, j in N\‍(N_0 & N_1)
    2565 */
    2566
    2567 /* gets weight and profit of variables in modified transformed knapsack problem */
    2568 for( j = 0; j < nitems; j++ )
    2569 {
    2570 transprofits[j] *= weights[items[j]];
    2571 assert(SCIPisFeasPositive(scip, transprofits[j]));
    2572 }
    2573 }
    2574
    2575 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
    2576 * transformed knapsack problem using Dantzig's method and rounding down the solution.
    2577 * let z* be the solution, then
    2578 * j in C, if z*_j = 0 and
    2579 * i in N\C, if z*_j = 1.
    2580 */
    2581 SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
    2582 noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
    2583 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
    2584
    2585 /* constructs cover C (sum_{j in C} a_j > a_0) */
    2586 for( j = 0; j < *ncovervars; j++ )
    2587 {
    2588 (*coverweight) += weights[covervars[j]];
    2589 }
    2590
    2591 /* adds all variables from N_1 to C */
    2592 for( j = 0; j < nfixedones; j++ )
    2593 {
    2594 covervars[*ncovervars] = fixedones[j];
    2595 (*ncovervars)++;
    2596 (*coverweight) += weights[fixedones[j]];
    2597 }
    2598
    2599 /* adds all variables from N_0 to N\C */
    2600 for( j = 0; j < nfixedzeros; j++ )
    2601 {
    2602 noncovervars[*nnoncovervars] = fixedzeros[j];
    2603 (*nnoncovervars)++;
    2604 }
    2605 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
    2606 assert((*coverweight) > capacity);
    2607 *found = TRUE;
    2608
    2609 TERMINATE:
    2610 /* frees temporary memory */
    2611 SCIPfreeBufferArray(scip, &items);
    2612 SCIPfreeBufferArray(scip, &fixedzeros);
    2613 SCIPfreeBufferArray(scip, &fixedones);
    2614 SCIPfreeBufferArray(scip, &transprofits);
    2615 SCIPfreeBufferArray(scip, &transweights);
    2616
    2617 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
    2618
    2619 return SCIP_OKAY;
    2620}
    2621
    2622#ifndef NDEBUG
    2623/** checks if minweightidx is set correctly
    2624 */
    2625static
    2627 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2628 SCIP_Longint capacity, /**< capacity of knapsack */
    2629 int* covervars, /**< pointer to store cover variables */
    2630 int ncovervars, /**< pointer to store number of cover variables */
    2631 SCIP_Longint coverweight, /**< pointer to store weight of cover */
    2632 int minweightidx, /**< index of variable in cover variables with minimum weight */
    2633 int j /**< current index in cover variables */
    2634 )
    2635{
    2636 SCIP_Longint minweight;
    2637 int i;
    2638
    2639 assert(weights != NULL);
    2640 assert(covervars != NULL);
    2641 assert(ncovervars > 0);
    2642
    2643 minweight = weights[covervars[minweightidx]];
    2644
    2645 /* checks if all cover variables before index j have weight greater than minweight */
    2646 for( i = 0; i < j; i++ )
    2647 {
    2648 assert(weights[covervars[i]] > minweight);
    2649 if( weights[covervars[i]] <= minweight )
    2650 return FALSE;
    2651 }
    2652
    2653 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
    2654 for( i = 0; i < j; i++ )
    2655 {
    2656 assert(coverweight - weights[covervars[i]] <= capacity);
    2657 if( coverweight - weights[covervars[i]] > capacity )
    2658 return FALSE;
    2659 }
    2660 return TRUE;
    2661}
    2662#endif
    2663
    2664
    2665/** gets partition \f$(C_1,C_2)\f$ of minimal cover \f$C\f$, i.e. \f$C_1 \cup C_2 = C\f$ and \f$C_1 \cap C_2 = \emptyset\f$,
    2666 * with \f$C_1\f$ not empty; chooses partition as follows \f$C_2 = \{ j \in C : x^*_j = 1 \}\f$ and \f$C_1 = C \setminus C_2\f$
    2667 */
    2668static
    2670 SCIP* scip, /**< SCIP data structure */
    2671 SCIP_Real* solvals, /**< solution values of all problem variables */
    2672 int* covervars, /**< cover variables */
    2673 int ncovervars, /**< number of cover variables */
    2674 int* varsC1, /**< pointer to store variables in C1 */
    2675 int* varsC2, /**< pointer to store variables in C2 */
    2676 int* nvarsC1, /**< pointer to store number of variables in C1 */
    2677 int* nvarsC2 /**< pointer to store number of variables in C2 */
    2678 )
    2679{
    2680 int j;
    2681
    2682 assert(scip != NULL);
    2683 assert(ncovervars >= 0);
    2684 assert(solvals != NULL);
    2685 assert(covervars != NULL);
    2686 assert(varsC1 != NULL);
    2687 assert(varsC2 != NULL);
    2688 assert(nvarsC1 != NULL);
    2689 assert(nvarsC2 != NULL);
    2690
    2691 *nvarsC1 = 0;
    2692 *nvarsC2 = 0;
    2693 for( j = 0; j < ncovervars; j++ )
    2694 {
    2695 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
    2696
    2697 /* variable has solution value one */
    2698 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
    2699 {
    2700 varsC2[*nvarsC2] = covervars[j];
    2701 (*nvarsC2)++;
    2702 }
    2703 /* variable has solution value less than one */
    2704 else
    2705 {
    2706 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
    2707 varsC1[*nvarsC1] = covervars[j];
    2708 (*nvarsC1)++;
    2709 }
    2710 }
    2711 assert((*nvarsC1) + (*nvarsC2) == ncovervars);
    2712}
    2713
    2714/** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
    2715 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
    2716 */
    2717static
    2719 SCIP* scip, /**< SCIP data structure */
    2720 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2721 int* varsC1, /**< pointer to store variables in C1 */
    2722 int* varsC2, /**< pointer to store variables in C2 */
    2723 int* nvarsC1, /**< pointer to store number of variables in C1 */
    2724 int* nvarsC2 /**< pointer to store number of variables in C2 */
    2725 )
    2726{
    2727 SCIP_Real* sortkeysC2;
    2728 int j;
    2729
    2730 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
    2731 assert(*nvarsC2 > 0);
    2732
    2733 /* allocates temporary memory */
    2734 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
    2735
    2736 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
    2737 for( j = 0; j < *nvarsC2; j++ )
    2738 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
    2739 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
    2740
    2741 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
    2742 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
    2743 while( *nvarsC1 < 2 && *nvarsC2 > 0 )
    2744 {
    2745 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
    2746 (*nvarsC1)++;
    2747 (*nvarsC2)--;
    2748 }
    2749
    2750 /* frees temporary memory */
    2751 SCIPfreeBufferArray(scip, &sortkeysC2);
    2752
    2753 return SCIP_OKAY;
    2754}
    2755
    2756/** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
    2757static
    2759 SCIP* scip, /**< SCIP data structure */
    2760 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2761 int* varsC1, /**< pointer to store variables in C1 */
    2762 int* varsC2, /**< pointer to store variables in C2 */
    2763 int* nvarsC1, /**< pointer to store number of variables in C1 */
    2764 int* nvarsC2 /**< pointer to store number of variables in C2 */
    2765 )
    2766{
    2767 SCIP_Real* sortkeysC2;
    2768 int j;
    2769
    2770 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
    2771 assert(*nvarsC2 > 0);
    2772
    2773 /* allocates temporary memory */
    2774 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
    2775
    2776 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
    2777 for( j = 0; j < *nvarsC2; j++ )
    2778 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
    2779 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
    2780
    2781 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
    2782 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
    2783 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
    2784 (*nvarsC1)++;
    2785 (*nvarsC2)--;
    2786
    2787 /* frees temporary memory */
    2788 SCIPfreeBufferArray(scip, &sortkeysC2);
    2789
    2790 return SCIP_OKAY;
    2791}
    2792
    2793
    2794/** gets partition \f$(F,R)\f$ of \f$N \setminus C\f$ where \f$C\f$ is a minimal cover, i.e. \f$F \cup R = N \setminus C\f$
    2795 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
    2796 * \f$F = (N \setminus C) \setminus F\f$
    2797 */
    2798static
    2800 SCIP* scip, /**< SCIP data structure */
    2801 SCIP_Real* solvals, /**< solution values of all problem variables */
    2802 int* noncovervars, /**< noncover variables */
    2803 int nnoncovervars, /**< number of noncover variables */
    2804 int* varsF, /**< pointer to store variables in F */
    2805 int* varsR, /**< pointer to store variables in R */
    2806 int* nvarsF, /**< pointer to store number of variables in F */
    2807 int* nvarsR /**< pointer to store number of variables in R */
    2808 )
    2809{
    2810 int j;
    2811
    2812 assert(scip != NULL);
    2813 assert(nnoncovervars >= 0);
    2814 assert(solvals != NULL);
    2815 assert(noncovervars != NULL);
    2816 assert(varsF != NULL);
    2817 assert(varsR != NULL);
    2818 assert(nvarsF != NULL);
    2819 assert(nvarsR != NULL);
    2820
    2821 *nvarsF = 0;
    2822 *nvarsR = 0;
    2823
    2824 for( j = 0; j < nnoncovervars; j++ )
    2825 {
    2826 /* variable has solution value zero */
    2827 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
    2828 {
    2829 varsR[*nvarsR] = noncovervars[j];
    2830 (*nvarsR)++;
    2831 }
    2832 /* variable has solution value greater than zero */
    2833 else
    2834 {
    2835 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
    2836 varsF[*nvarsF] = noncovervars[j];
    2837 (*nvarsF)++;
    2838 }
    2839 }
    2840 assert((*nvarsF) + (*nvarsR) == nnoncovervars);
    2841}
    2842
    2843/** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
    2844 * lifting procedure
    2845 */
    2846static
    2848 SCIP* scip, /**< SCIP data structure */
    2849 SCIP_Real* solvals, /**< solution values of all problem variables */
    2850 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2851 int* varsF, /**< pointer to store variables in F */
    2852 int* varsC2, /**< pointer to store variables in C2 */
    2853 int* varsR, /**< pointer to store variables in R */
    2854 int nvarsF, /**< number of variables in F */
    2855 int nvarsC2, /**< number of variables in C2 */
    2856 int nvarsR /**< number of variables in R */
    2857 )
    2858{
    2859 SORTKEYPAIR** sortkeypairsF;
    2860 SORTKEYPAIR* sortkeypairsFstore;
    2861 SCIP_Real* sortkeysC2;
    2862 SCIP_Real* sortkeysR;
    2863 int j;
    2864
    2865 assert(scip != NULL);
    2866 assert(solvals != NULL);
    2867 assert(weights != NULL);
    2868 assert(varsF != NULL);
    2869 assert(varsC2 != NULL);
    2870 assert(varsR != NULL);
    2871 assert(nvarsF >= 0);
    2872 assert(nvarsC2 >= 0);
    2873 assert(nvarsR >= 0);
    2874
    2875 /* allocates temporary memory */
    2876 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
    2877 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
    2878 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
    2879 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
    2880
    2881 /* gets sorting key for variables in F corresponding to the following lifting sequence
    2882 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
    2883 * x*_1 >= x*_2 >= ... >= x*_|F|
    2884 * in case of equality uses
    2885 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
    2886 */
    2887 for( j = 0; j < nvarsF; j++ )
    2888 {
    2889 sortkeypairsF[j] = &(sortkeypairsFstore[j]);
    2890 sortkeypairsF[j]->key1 = solvals[varsF[j]];
    2891 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
    2892 }
    2893
    2894 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
    2895 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
    2896 */
    2897 for( j = 0; j < nvarsC2; j++ )
    2898 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
    2899
    2900 /* gets sorting key for variables in R corresponding to the following lifting sequence
    2901 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
    2902 */
    2903 for( j = 0; j < nvarsR; j++ )
    2904 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
    2905
    2906 /* sorts F, C2 and R */
    2907 if( nvarsF > 0 )
    2908 {
    2909 SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
    2910 }
    2911 if( nvarsC2 > 0 )
    2912 {
    2913 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
    2914 }
    2915 if( nvarsR > 0)
    2916 {
    2917 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
    2918 }
    2919
    2920 /* frees temporary memory */
    2921 SCIPfreeBufferArray(scip, &sortkeysR);
    2922 SCIPfreeBufferArray(scip, &sortkeysC2);
    2923 SCIPfreeBufferArray(scip, &sortkeypairsFstore);
    2924 SCIPfreeBufferArray(scip, &sortkeypairsF);
    2925
    2926 return SCIP_OKAY;
    2927}
    2928
    2929/** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
    2930 * for the sequential GUB wise lifting procedure
    2931 */
    2932static
    2934 SCIP* scip, /**< SCIP data structure */
    2935 SCIP_GUBSET* gubset, /**< GUB set data structure */
    2936 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
    2937 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2938 int* varsC1, /**< variables in C1 */
    2939 int* varsC2, /**< variables in C2 */
    2940 int* varsF, /**< variables in F */
    2941 int* varsR, /**< variables in R */
    2942 int nvarsC1, /**< number of variables in C1 */
    2943 int nvarsC2, /**< number of variables in C2 */
    2944 int nvarsF, /**< number of variables in F */
    2945 int nvarsR, /**< number of variables in R */
    2946 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
    2947 int* gubconsGC2, /**< pointer to store GUBs in GC2 */
    2948 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
    2949 int* gubconsGR, /**< pointer to store GUBs in GR */
    2950 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
    2951 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
    2952 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
    2953 int* ngubconsGR, /**< pointer to store number of GUBs in GR */
    2954 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
    2955 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
    2956 )
    2957{
    2958 SORTKEYPAIR** sortkeypairsGFC1;
    2959 SORTKEYPAIR* sortkeypairsGFC1store;
    2960 SCIP_Real* sortkeysC1;
    2961 SCIP_Real* sortkeysC2;
    2962 SCIP_Real* sortkeysR;
    2963 int* nC1varsingubcons;
    2964 int var;
    2965 int gubconsidx;
    2966 int varidx;
    2967 int ngubconss;
    2968 int ngubconsGOC1;
    2969 int targetvar;
    2970#ifndef NDEBUG
    2971 int nvarsprocessed = 0;
    2972#endif
    2973 int i;
    2974 int j;
    2975
    2976#if GUBSPLITGNC1GUBS
    2977 SCIP_Bool gubconswithF;
    2978 int origngubconss;
    2979 origngubconss = gubset->ngubconss;
    2980#endif
    2981
    2982 assert(scip != NULL);
    2983 assert(gubset != NULL);
    2984 assert(solvals != NULL);
    2985 assert(weights != NULL);
    2986 assert(varsC1 != NULL);
    2987 assert(varsC2 != NULL);
    2988 assert(varsF != NULL);
    2989 assert(varsR != NULL);
    2990 assert(nvarsC1 > 0);
    2991 assert(nvarsC2 >= 0);
    2992 assert(nvarsF >= 0);
    2993 assert(nvarsR >= 0);
    2994 assert(gubconsGC1 != NULL);
    2995 assert(gubconsGC2 != NULL);
    2996 assert(gubconsGFC1 != NULL);
    2997 assert(gubconsGR != NULL);
    2998 assert(ngubconsGC1 != NULL);
    2999 assert(ngubconsGC2 != NULL);
    3000 assert(ngubconsGFC1 != NULL);
    3001 assert(ngubconsGR != NULL);
    3002 assert(maxgubvarssize != NULL);
    3003
    3004 ngubconss = gubset->ngubconss;
    3005 ngubconsGOC1 = 0;
    3006
    3007 /* GUBs are categorized into different types according to the variables in volved
    3008 * - GOC1: involves variables in C1 only -- no C2, R, F
    3009 * - GNC1: involves variables in C1 and F (and R) -- no C2
    3010 * - GF: involves variables in F (and R) only -- no C1, C2
    3011 * - GC2: involves variables in C2 only -- no C1, R, F
    3012 * - GR: involves variables in R only -- no C1, C2, F
    3013 * which requires splitting GUBs in case they include variable in F and R.
    3014 *
    3015 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
    3016 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
    3017 * - second ordering level is
    3018 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
    3019 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
    3020 * GR: non-increasing max{ a_k : k in GR_j}
    3021 *
    3022 * in additon, another GUB union, which is helpful for the lifting procedure, is formed
    3023 * - GC1: GUBs of category GOC1 and GNC1
    3024 * with second ordering level non-decreasing min{ a_k : k in GC1_j };
    3025 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
    3026 */
    3027
    3028 /* allocates temporary memory */
    3029 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
    3030 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
    3031 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
    3032
    3033 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
    3034 * - F: non-increasing x*_j and non-increasing a_j in case of equality
    3035 * - C2: non-increasing a_j
    3036 * - R: non-increasing a_j
    3037 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
    3038 */
    3039
    3040 /* gets sorting key for variables in C1 corresponding to the following ordering
    3041 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
    3042 */
    3043 for( j = 0; j < nvarsC1; j++ )
    3044 {
    3045 /* gets sortkeys */
    3046 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
    3047
    3048 /* update status of variable in its gub constraint */
    3049 gubconsidx = gubset->gubconssidx[varsC1[j]];
    3050 varidx = gubset->gubvarsidx[varsC1[j]];
    3051 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
    3052 }
    3053
    3054 /* gets sorting key for variables in F corresponding to the following ordering
    3055 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
    3056 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
    3057 * and updates status of each variable in F in GUB set data structure
    3058 */
    3059 for( j = 0; j < nvarsF; j++ )
    3060 {
    3061 /* update status of variable in its gub constraint */
    3062 gubconsidx = gubset->gubconssidx[varsF[j]];
    3063 varidx = gubset->gubvarsidx[varsF[j]];
    3064 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
    3065 }
    3066
    3067 /* gets sorting key for variables in C2 corresponding to the following ordering
    3068 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
    3069 * and updates status of each variable in F in GUB set data structure
    3070 */
    3071 for( j = 0; j < nvarsC2; j++ )
    3072 {
    3073 /* gets sortkeys */
    3074 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
    3075
    3076 /* update status of variable in its gub constraint */
    3077 gubconsidx = gubset->gubconssidx[varsC2[j]];
    3078 varidx = gubset->gubvarsidx[varsC2[j]];
    3079 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
    3080 }
    3081
    3082 /* gets sorting key for variables in R corresponding to the following ordering
    3083 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
    3084 * and updates status of each variable in F in GUB set data structure
    3085 */
    3086 for( j = 0; j < nvarsR; j++ )
    3087 {
    3088 /* gets sortkeys */
    3089 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
    3090
    3091 /* update status of variable in its gub constraint */
    3092 gubconsidx = gubset->gubconssidx[varsR[j]];
    3093 varidx = gubset->gubvarsidx[varsR[j]];
    3094 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
    3095 }
    3096
    3097 /* sorts C1, F, C2 and R */
    3098 assert(nvarsC1 > 0);
    3099 SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
    3100
    3101 if( nvarsC2 > 0 )
    3102 {
    3103 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
    3104 }
    3105 if( nvarsR > 0)
    3106 {
    3107 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
    3108 }
    3109
    3110 /* frees temporary memory */
    3111 SCIPfreeBufferArray(scip, &sortkeysR);
    3112 SCIPfreeBufferArray(scip, &sortkeysC2);
    3113 SCIPfreeBufferArray(scip, &sortkeysC1);
    3114
    3115 /* allocate and initialize temporary memory for sorting GUB constraints */
    3116 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
    3117 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
    3118 SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
    3119 BMSclearMemoryArray(nC1varsingubcons, ngubconss);
    3120 for( i = 0; i < ngubconss; i++)
    3121 {
    3122 sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
    3123 sortkeypairsGFC1[i]->key1 = 0.0;
    3124 sortkeypairsGFC1[i]->key2 = 0.0;
    3125 }
    3126 *ngubconsGC1 = 0;
    3127 *ngubconsGC2 = 0;
    3128 *ngubconsGFC1 = 0;
    3129 *ngubconsGR = 0;
    3130 *ngubconscapexceed = 0;
    3131 *maxgubvarssize = 0;
    3132
    3133#ifndef NDEBUG
    3134 for( i = 0; i < gubset->ngubconss; i++ )
    3135 assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
    3136#endif
    3137
    3138 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
    3139 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
    3140 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
    3141 * non-increasing number of variables in F, and
    3142 * non-increasing max{x*_k : k in GFC1_j} in case of equality
    3143 */
    3144 for( i = 0; i < nvarsC1; i++ )
    3145 {
    3146 int nvarsC1capexceed;
    3147
    3148 nvarsC1capexceed = 0;
    3149
    3150 var = varsC1[i];
    3151 gubconsidx = gubset->gubconssidx[var];
    3152 varidx = gubset->gubvarsidx[var];
    3153
    3154 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
    3155 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
    3156
    3157 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
    3158 * note that variables in C1 are already sorted by non-decreasing weigth
    3159 */
    3160 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
    3161 GUBsetSwapVars(scip, gubset, var, targetvar);
    3162 nC1varsingubcons[gubconsidx]++;
    3163
    3164 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
    3165 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
    3166 {
    3167 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
    3168 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    3169 continue;
    3170 }
    3171
    3172 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
    3173 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
    3174 */
    3175#if GUBSPLITGNC1GUBS
    3176 gubconswithF = FALSE;
    3177#endif
    3178 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
    3179 {
    3180 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
    3181
    3182 /* C1-variable: update number of C1/capacity exceeding variables */
    3183 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
    3184 {
    3185 nvarsC1capexceed++;
    3186#ifndef NDEBUG
    3187 nvarsprocessed++;
    3188#endif
    3189 }
    3190 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
    3191 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
    3192 {
    3193#if GUBSPLITGNC1GUBS
    3194 gubconswithF = TRUE;
    3195#endif
    3196 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
    3197
    3198 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
    3199 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
    3200 }
    3201 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
    3202 {
    3203 nvarsC1capexceed++;
    3204 }
    3205 else
    3206 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
    3207 }
    3208
    3209 /* update set of GC1 GUBs */
    3210 gubconsGC1[*ngubconsGC1] = gubconsidx;
    3211 (*ngubconsGC1)++;
    3212
    3213 /* update maximum size of all GUB constraints */
    3214 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
    3215 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
    3216
    3217 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
    3218 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
    3219 {
    3220 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
    3221 ngubconsGOC1++;
    3222 }
    3223 else
    3224 {
    3225#if GUBSPLITGNC1GUBS
    3226 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
    3227 if( !gubconswithF )
    3228 {
    3229 GUBVARSTATUS movevarstatus;
    3230
    3231 assert(gubset->ngubconss < gubset->nvars);
    3232
    3233 /* create a new GUB for GR part of splitting */
    3234 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
    3235 gubset->ngubconss++;
    3236 ngubconss = gubset->ngubconss;
    3237
    3238 /* fill GR with R variables in current GUB */
    3239 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
    3240 {
    3241 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
    3242 if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
    3243 {
    3244 assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
    3245 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
    3246 gubconsidx, ngubconss-1) );
    3247 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
    3248 movevarstatus;
    3249 }
    3250 }
    3251
    3252 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
    3253 ngubconsGOC1++;
    3254
    3256 gubconsGR[*ngubconsGR] = ngubconss-1;
    3257 (*ngubconsGR)++;
    3258 }
    3259 /* variables in C1, F, and maybe R: GNC1 GUB */
    3260 else
    3261 {
    3262 assert(gubconswithF);
    3263
    3264 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
    3265 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
    3266 (*ngubconsGFC1)++;
    3267 }
    3268#else
    3269 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
    3270 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
    3271 (*ngubconsGFC1)++;
    3272#endif
    3273 }
    3274 }
    3275
    3276 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
    3277 * are already sorted correctly
    3278 */
    3279 for( i = 0; i < nvarsC2; i++ )
    3280 {
    3281 var = varsC2[i];
    3282 gubconsidx = gubset->gubconssidx[var];
    3283 varidx = gubset->gubvarsidx[var];
    3284
    3285 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
    3286 assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
    3287 assert(varidx == 0);
    3288 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
    3289 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
    3290
    3291 /* set status of GC2 GUB */
    3292 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
    3293
    3294 /* update group of GC2 GUBs */
    3295 gubconsGC2[*ngubconsGC2] = gubconsidx;
    3296 (*ngubconsGC2)++;
    3297
    3298 /* update maximum size of all GUB constraints */
    3299 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
    3300 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
    3301
    3302#ifndef NDEBUG
    3303 nvarsprocessed++;
    3304#endif
    3305 }
    3306
    3307 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
    3308 * non-increasing number of variables in F, and
    3309 * non-increasing max{x*_k : k in GFC1_j} in case of equality
    3310 */
    3311 for( i = 0; i < nvarsF; i++ )
    3312 {
    3313 var = varsF[i];
    3314 gubconsidx = gubset->gubconssidx[var];
    3315 varidx = gubset->gubvarsidx[var];
    3316
    3317 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
    3318 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
    3319
    3320#ifndef NDEBUG
    3321 nvarsprocessed++;
    3322#endif
    3323
    3324 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
    3325 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
    3326 {
    3327 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
    3328 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    3329 continue;
    3330 }
    3331
    3332 /* set status of GF GUB */
    3333 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
    3334
    3335 /* update sorting key of corresponding GFC1 GUB */
    3336 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
    3337 {
    3338 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
    3339 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
    3340
    3341 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
    3342 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
    3343 {
    3344 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
    3345
    3346 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
    3347 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
    3348 }
    3349 }
    3350
    3351 /* update set of GFC1 GUBs */
    3352 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
    3353 (*ngubconsGFC1)++;
    3354
    3355 /* update maximum size of all GUB constraints */
    3356 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
    3357 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
    3358 }
    3359
    3360 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
    3361 * correctly
    3362 */
    3363 for( i = 0; i < nvarsR; i++ )
    3364 {
    3365 var = varsR[i];
    3366 gubconsidx = gubset->gubconssidx[var];
    3367 varidx = gubset->gubvarsidx[var];
    3368
    3369 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
    3370 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
    3371
    3372#ifndef NDEBUG
    3373 nvarsprocessed++;
    3374#endif
    3375
    3376 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
    3377 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
    3378 {
    3379 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
    3380 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
    3381 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    3382 continue;
    3383 }
    3384
    3385 /* set status of GR GUB */
    3386 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
    3387
    3388 /* update set of GR GUBs */
    3389 gubconsGR[*ngubconsGR] = gubconsidx;
    3390 (*ngubconsGR)++;
    3391
    3392 /* update maximum size of all GUB constraints */
    3393 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
    3394 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
    3395 }
    3396 assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
    3397
    3398 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
    3399 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
    3400 assert(*ngubconscapexceed >= 0);
    3401#ifndef NDEBUG
    3402 {
    3403 int check;
    3404
    3405 check = 0;
    3406
    3407 /* remaining not handled GUBs should only contain capacity exceeding variables */
    3408 for( i = 0; i < ngubconss; i++ )
    3409 {
    3410 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
    3411 check++;
    3412 }
    3413 assert(check == *ngubconscapexceed);
    3414 }
    3415#endif
    3416
    3417 /* sort GFCI GUBs according to computed sorting keys */
    3418 if( (*ngubconsGFC1) > 0 )
    3419 {
    3420 SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
    3421 }
    3422
    3423 /* free temporary memory */
    3424#if GUBSPLITGNC1GUBS
    3425 ngubconss = origngubconss;
    3426#endif
    3427 SCIPfreeBufferArray(scip, &nC1varsingubcons);
    3428 SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
    3429 SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
    3430
    3431 return SCIP_OKAY;
    3432}
    3433
    3434/** enlarges minweight table to at least the given length */
    3435static
    3437 SCIP* scip, /**< SCIP data structure */
    3438 SCIP_Longint** minweightsptr, /**< pointer to minweights table */
    3439 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
    3440 int* minweightssize, /**< pointer to current size of minweights table */
    3441 int newlen /**< new length of minweights table */
    3442 )
    3443{
    3444 int j;
    3445
    3446 assert(minweightsptr != NULL);
    3447 assert(*minweightsptr != NULL);
    3448 assert(minweightslen != NULL);
    3449 assert(*minweightslen >= 0);
    3450 assert(minweightssize != NULL);
    3451 assert(*minweightssize >= 0);
    3452
    3453 if( newlen > *minweightssize )
    3454 {
    3455 int newsize;
    3456
    3457 /* reallocate table memory */
    3458 newsize = SCIPcalcMemGrowSize(scip, newlen);
    3459 SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
    3460 *minweightssize = newsize;
    3461 }
    3462 assert(newlen <= *minweightssize);
    3463
    3464 /* initialize new elements */
    3465 for( j = *minweightslen; j < newlen; ++j )
    3466 (*minweightsptr)[j] = SCIP_LONGINT_MAX;
    3467 *minweightslen = newlen;
    3468
    3469 return SCIP_OKAY;
    3470}
    3471
    3472/** lifts given inequality
    3473 * sum_{j in M_1} x_j <= alpha_0
    3474 * valid for
    3475 * S^0 = { x in {0,1}^|M_1| : sum_{j in M_1} a_j x_j <= a_0 - sum_{j in M_2} a_j }
    3476 * to a valid inequality
    3477 * sum_{j in M_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in M_2} alpha_j x_j + sum_{j in R} alpha_j x_j
    3478 * <= alpha_0 + sum_{j in M_2} alpha_j
    3479 * for
    3480 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
    3481 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
    3482 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
    3483 * extended weight inequalities.
    3484 */
    3485static
    3487 SCIP* scip, /**< SCIP data structure */
    3488 SCIP_VAR** vars, /**< variables in knapsack constraint */
    3489 int nvars, /**< number of variables in knapsack constraint */
    3490 int ntightened, /**< number of variables with tightened upper bound */
    3491 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    3492 SCIP_Longint capacity, /**< capacity of knapsack */
    3493 SCIP_Real* solvals, /**< solution values of all problem variables */
    3494 int* varsM1, /**< variables in M_1 */
    3495 int* varsM2, /**< variables in M_2 */
    3496 int* varsF, /**< variables in F */
    3497 int* varsR, /**< variables in R */
    3498 int nvarsM1, /**< number of variables in M_1 */
    3499 int nvarsM2, /**< number of variables in M_2 */
    3500 int nvarsF, /**< number of variables in F */
    3501 int nvarsR, /**< number of variables in R */
    3502 int alpha0, /**< rights hand side of given valid inequality */
    3503 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
    3504 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
    3505 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
    3506 )
    3507{
    3508 SCIP_Longint* minweights;
    3509 SCIP_Real* sortkeys;
    3510 SCIP_Longint fixedonesweight;
    3511 int minweightssize;
    3512 int minweightslen;
    3513 int j;
    3514 int w;
    3515
    3516 assert(scip != NULL);
    3517 assert(vars != NULL);
    3518 assert(nvars >= 0);
    3519 assert(weights != NULL);
    3520 assert(capacity >= 0);
    3521 assert(solvals != NULL);
    3522 assert(varsM1 != NULL);
    3523 assert(varsM2 != NULL);
    3524 assert(varsF != NULL);
    3525 assert(varsR != NULL);
    3526 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
    3527 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
    3528 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
    3529 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
    3530 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
    3531 assert(alpha0 >= 0);
    3532 assert(liftcoefs != NULL);
    3533 assert(cutact != NULL);
    3534 assert(liftrhs != NULL);
    3535
    3536 /* allocates temporary memory */
    3537 minweightssize = nvarsM1 + 1;
    3538 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
    3539 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
    3540
    3541 /* initializes data structures */
    3542 BMSclearMemoryArray(liftcoefs, nvars);
    3543 *cutact = 0.0;
    3544
    3545 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
    3546 * and calculates activity of the current valid inequality
    3547 */
    3548 for( j = 0; j < nvarsM1; j++ )
    3549 {
    3550 assert(liftcoefs[varsM1[j]] == 0);
    3551 liftcoefs[varsM1[j]] = 1;
    3552 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
    3553 (*cutact) += solvals[varsM1[j]];
    3554 }
    3555
    3556 SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
    3557
    3558 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
    3559 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
    3560 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
    3561 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
    3562 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
    3563 */
    3564 minweights[0] = 0;
    3565 for( w = 1; w <= nvarsM1; w++ )
    3566 minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
    3567 minweightslen = nvarsM1 + 1;
    3568
    3569 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
    3570 fixedonesweight = 0;
    3571 for( j = 0; j < nvarsM2; j++ )
    3572 fixedonesweight += weights[varsM2[j]];
    3573 assert(fixedonesweight >= 0);
    3574
    3575 /* initializes right hand side of lifted valid inequality */
    3576 *liftrhs = alpha0;
    3577
    3578 /* sequentially up-lifts all variables in F: */
    3579 for( j = 0; j < nvarsF; j++ )
    3580 {
    3581 SCIP_Longint weight;
    3582 int liftvar;
    3583 int liftcoef;
    3584 int z;
    3585
    3586 liftvar = varsF[j];
    3587 weight = weights[liftvar];
    3588 assert(liftvar >= 0 && liftvar < nvars);
    3589 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
    3590 assert(weight > 0);
    3591
    3592 /* knapsack problem is infeasible:
    3593 * sets z = 0
    3594 */
    3595 if( capacity - fixedonesweight - weight < 0 )
    3596 {
    3597 z = 0;
    3598 }
    3599 /* knapsack problem is feasible:
    3600 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
    3601 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
    3602 */
    3603 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
    3604 {
    3605 z = *liftrhs;
    3606 }
    3607 /* knapsack problem is feasible:
    3608 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
    3609 */
    3610 else
    3611 {
    3612 int left;
    3613 int right;
    3614 int middle;
    3615
    3616 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
    3617 left = 0;
    3618 right = (*liftrhs) + 1;
    3619 while( left < right - 1 )
    3620 {
    3621 middle = (left + right) / 2;
    3622 assert(0 <= middle && middle < minweightslen);
    3623 if( minweights[middle] <= capacity - fixedonesweight - weight )
    3624 left = middle;
    3625 else
    3626 right = middle;
    3627 }
    3628 assert(left == right - 1);
    3629 assert(0 <= left && left < minweightslen);
    3630 assert(minweights[left] <= capacity - fixedonesweight - weight );
    3631 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
    3632
    3633 /* now z = left */
    3634 z = left;
    3635 assert(z <= *liftrhs);
    3636 }
    3637
    3638 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
    3639 liftcoef = (*liftrhs) - z;
    3640 liftcoefs[liftvar] = liftcoef;
    3641 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
    3642
    3643 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
    3644 if( liftcoef == 0 )
    3645 continue;
    3646
    3647 /* updates activity of current valid inequality */
    3648 (*cutact) += liftcoef * solvals[liftvar];
    3649
    3650 /* enlarges current minweight table:
    3651 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
    3652 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
    3653 * and sets minweights_i[w] = infinity for
    3654 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
    3655 */
    3656 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
    3657
    3658 /* updates minweight table: minweight_i+1[w] =
    3659 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
    3660 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
    3661 */
    3662 for( w = minweightslen - 1; w >= 0; w-- )
    3663 {
    3665 if( w < liftcoef )
    3666 {
    3667 min = MIN(minweights[w], weight);
    3668 minweights[w] = min;
    3669 }
    3670 else
    3671 {
    3672 assert(w >= liftcoef);
    3673 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
    3674 minweights[w] = min;
    3675 }
    3676 }
    3677 }
    3678 assert(minweights[0] == 0);
    3679
    3680 /* sequentially down-lifts all variables in M_2: */
    3681 for( j = 0; j < nvarsM2; j++ )
    3682 {
    3683 SCIP_Longint weight;
    3684 int liftvar;
    3685 int liftcoef;
    3686 int left;
    3687 int right;
    3688 int middle;
    3689 int z;
    3690
    3691 liftvar = varsM2[j];
    3692 weight = weights[liftvar];
    3693 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
    3694 assert(liftvar >= 0 && liftvar < nvars);
    3695 assert(weight > 0);
    3696
    3697 /* uses binary search to find
    3698 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
    3699 */
    3700 left = 0;
    3701 right = minweightslen;
    3702 while( left < right - 1 )
    3703 {
    3704 middle = (left + right) / 2;
    3705 assert(0 <= middle && middle < minweightslen);
    3706 if( minweights[middle] <= capacity - fixedonesweight + weight )
    3707 left = middle;
    3708 else
    3709 right = middle;
    3710 }
    3711 assert(left == right - 1);
    3712 assert(0 <= left && left < minweightslen);
    3713 assert(minweights[left] <= capacity - fixedonesweight + weight );
    3714 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
    3715
    3716 /* now z = left */
    3717 z = left;
    3718 assert(z >= *liftrhs);
    3719
    3720 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
    3721 liftcoef = z - (*liftrhs);
    3722 liftcoefs[liftvar] = liftcoef;
    3723 assert(liftcoef >= 0);
    3724
    3725 /* updates sum of weights of variables fixed to one */
    3726 fixedonesweight -= weight;
    3727
    3728 /* updates right-hand side of current valid inequality */
    3729 (*liftrhs) += liftcoef;
    3730 assert(*liftrhs >= alpha0);
    3731
    3732 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
    3733 if( liftcoef == 0 )
    3734 continue;
    3735
    3736 /* updates activity of current valid inequality */
    3737 (*cutact) += liftcoef * solvals[liftvar];
    3738
    3739 /* enlarges current minweight table:
    3740 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
    3741 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
    3742 * and sets minweights_i[w] = infinity for
    3743 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
    3744 */
    3745 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
    3746
    3747 /* updates minweight table: minweight_i+1[w] =
    3748 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
    3749 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
    3750 */
    3751 for( w = minweightslen - 1; w >= 0; w-- )
    3752 {
    3754 if( w < liftcoef )
    3755 {
    3756 min = MIN(minweights[w], weight);
    3757 minweights[w] = min;
    3758 }
    3759 else
    3760 {
    3761 assert(w >= liftcoef);
    3762 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
    3763 minweights[w] = min;
    3764 }
    3765 }
    3766 }
    3767 assert(fixedonesweight == 0);
    3768 assert(*liftrhs >= alpha0);
    3769
    3770 /* sequentially up-lifts all variables in R: */
    3771 for( j = 0; j < nvarsR; j++ )
    3772 {
    3773 SCIP_Longint weight;
    3774 int liftvar;
    3775 int liftcoef;
    3776 int z;
    3777
    3778 liftvar = varsR[j];
    3779 weight = weights[liftvar];
    3780 assert(liftvar >= 0 && liftvar < nvars);
    3781 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
    3782 assert(weight > 0);
    3783 assert(capacity - weight >= 0);
    3784 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
    3785
    3786 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
    3787 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
    3788 */
    3789 if( minweights[*liftrhs] <= capacity - weight )
    3790 {
    3791 z = *liftrhs;
    3792 }
    3793 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
    3794 */
    3795 else
    3796 {
    3797 int left;
    3798 int right;
    3799 int middle;
    3800
    3801 left = 0;
    3802 right = (*liftrhs) + 1;
    3803 while( left < right - 1)
    3804 {
    3805 middle = (left + right) / 2;
    3806 assert(0 <= middle && middle < minweightslen);
    3807 if( minweights[middle] <= capacity - weight )
    3808 left = middle;
    3809 else
    3810 right = middle;
    3811 }
    3812 assert(left == right - 1);
    3813 assert(0 <= left && left < minweightslen);
    3814 assert(minweights[left] <= capacity - weight );
    3815 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
    3816
    3817 /* now z = left */
    3818 z = left;
    3819 assert(z <= *liftrhs);
    3820 }
    3821
    3822 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
    3823 liftcoef = (*liftrhs) - z;
    3824 liftcoefs[liftvar] = liftcoef;
    3825 assert(liftcoef >= 0 && liftcoef <= *liftrhs);
    3826
    3827 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
    3828 if( liftcoef == 0 )
    3829 continue;
    3830
    3831 /* updates activity of current valid inequality */
    3832 (*cutact) += liftcoef * solvals[liftvar];
    3833
    3834 /* updates minweight table: minweight_i+1[w] =
    3835 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
    3836 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
    3837 */
    3838 for( w = *liftrhs; w >= 0; w-- )
    3839 {
    3841 if( w < liftcoef )
    3842 {
    3843 min = MIN(minweights[w], weight);
    3844 minweights[w] = min;
    3845 }
    3846 else
    3847 {
    3848 assert(w >= liftcoef);
    3849 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
    3850 minweights[w] = min;
    3851 }
    3852 }
    3853 }
    3854
    3855 /* frees temporary memory */
    3856 SCIPfreeBufferArray(scip, &sortkeys);
    3857 SCIPfreeBufferArray(scip, &minweights);
    3858
    3859 return SCIP_OKAY;
    3860}
    3861
    3862/** adds two minweight values in a safe way, i.e,, ensures no overflow */
    3863static
    3865 SCIP_Longint val1, /**< first value to add */
    3866 SCIP_Longint val2 /**< second value to add */
    3867 )
    3868{
    3869 assert(val1 >= 0);
    3870 assert(val2 >= 0);
    3871
    3872 if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
    3873 return SCIP_LONGINT_MAX;
    3874 else
    3875 {
    3876 assert(val1 <= SCIP_LONGINT_MAX - val2);
    3877 return (val1 + val2);
    3878 }
    3879}
    3880
    3881/** computes minweights table for lifting with GUBs by combining unfished and fished tables */
    3882static
    3884 SCIP_Longint* minweights, /**< minweight table to compute */
    3885 SCIP_Longint* finished, /**< given finished table */
    3886 SCIP_Longint* unfinished, /**< given unfinished table */
    3887 int minweightslen /**< length of minweight, finished, and unfinished tables */
    3888 )
    3889{
    3890 int w1;
    3891 int w2;
    3892
    3893 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
    3894 * note that finished and unfished arrays sorted by non-decreasing weight
    3895 */
    3896
    3897 /* initialize minweight with w2 = 0 */
    3898 w2 = 0;
    3899 assert(unfinished[w2] == 0);
    3900 for( w1 = 0; w1 < minweightslen; w1++ )
    3901 minweights[w1] = finished[w1];
    3902
    3903 /* consider w2 = 1, ..., minweightslen-1 */
    3904 for( w2 = 1; w2 < minweightslen; w2++ )
    3905 {
    3906 if( unfinished[w2] >= SCIP_LONGINT_MAX )
    3907 break;
    3908
    3909 for( w1 = 0; w1 < minweightslen - w2; w1++ )
    3910 {
    3911 SCIP_Longint temp;
    3912
    3913 temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
    3914 if( temp <= minweights[w1+w2] )
    3915 minweights[w1+w2] = temp;
    3916 }
    3917 }
    3918}
    3919
    3920/** lifts given inequality
    3921 * sum_{j in C_1} x_j <= alpha_0
    3922 * valid for
    3923 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j;
    3924 * sum_{j in Q_i} x_j <= 1, forall i in I }
    3925 * to a valid inequality
    3926 * sum_{j in C_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in C_2} alpha_j x_j + sum_{j in R} alpha_j x_j
    3927 * <= alpha_0 + sum_{j in C_2} alpha_j
    3928 * for
    3929 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0; sum_{j in Q_i} x_j <= 1, forall i in I };
    3930 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
    3931 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
    3932 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
    3933 */
    3934static
    3936 SCIP* scip, /**< SCIP data structure */
    3937 SCIP_GUBSET* gubset, /**< GUB set data structure */
    3938 SCIP_VAR** vars, /**< variables in knapsack constraint */
    3939 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
    3940 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    3941 SCIP_Longint capacity, /**< capacity of knapsack */
    3942 SCIP_Real* solvals, /**< solution values of all knapsack variables */
    3943 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
    3944 int* gubconsGC2, /**< GUBs in GC2 */
    3945 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
    3946 int* gubconsGR, /**< GUBs in GR */
    3947 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
    3948 int ngubconsGC2, /**< number of GUBs in GC2 */
    3949 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
    3950 int ngubconsGR, /**< number of GUBs in GR */
    3951 int alpha0, /**< rights hand side of given valid inequality */
    3952 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
    3953 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
    3954 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
    3955 int maxgubvarssize /**< maximal size of GUB constraints */
    3956 )
    3957{
    3958 SCIP_Longint* minweights;
    3959 SCIP_Longint* finished;
    3960 SCIP_Longint* unfinished;
    3961 int* gubconsGOC1;
    3962 int* gubconsGNC1;
    3963 int* liftgubvars;
    3964 SCIP_Longint fixedonesweight;
    3965 SCIP_Longint weight;
    3966 SCIP_Longint weightdiff1;
    3967 SCIP_Longint weightdiff2;
    3969 int minweightssize;
    3970 int minweightslen;
    3971 int nvars;
    3972 int varidx;
    3973 int liftgubconsidx;
    3974 int liftvar;
    3975 int sumliftcoef;
    3976 int liftcoef;
    3977 int ngubconsGOC1;
    3978 int ngubconsGNC1;
    3979 int left;
    3980 int right;
    3981 int middle;
    3982 int nliftgubvars;
    3983 int tmplen;
    3984 int tmpsize;
    3985 int j;
    3986 int k;
    3987 int w;
    3988 int z;
    3989#ifndef NDEBUG
    3990 int ngubconss;
    3991 int nliftgubC1;
    3992
    3993 assert(gubset != NULL);
    3994 ngubconss = gubset->ngubconss;
    3995#else
    3996 assert(gubset != NULL);
    3997#endif
    3998
    3999 nvars = gubset->nvars;
    4000
    4001 assert(scip != NULL);
    4002 assert(vars != NULL);
    4003 assert(nvars >= 0);
    4004 assert(weights != NULL);
    4005 assert(capacity >= 0);
    4006 assert(solvals != NULL);
    4007 assert(gubconsGC1 != NULL);
    4008 assert(gubconsGC2 != NULL);
    4009 assert(gubconsGFC1 != NULL);
    4010 assert(gubconsGR != NULL);
    4011 assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
    4012 assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
    4013 assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
    4014 assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
    4015 assert(alpha0 >= 0);
    4016 assert(liftcoefs != NULL);
    4017 assert(cutact != NULL);
    4018 assert(liftrhs != NULL);
    4019
    4020 minweightssize = ngubconsGC1+1;
    4021
    4022 /* allocates temporary memory */
    4023 SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
    4024 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
    4025 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
    4026 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
    4027 SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
    4028 SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
    4029
    4030 /* initializes data structures */
    4031 BMSclearMemoryArray(liftcoefs, nvars);
    4032 *cutact = 0.0;
    4033
    4034 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
    4035 * valid inequality
    4036 */
    4037 ngubconsGOC1 = 0;
    4038 ngubconsGNC1 = 0;
    4039 for( j = 0; j < ngubconsGC1; j++ )
    4040 {
    4041 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
    4042 {
    4043 gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
    4044 ngubconsGOC1++;
    4045 }
    4046 else
    4047 {
    4048 assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    4049 gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
    4050 ngubconsGNC1++;
    4051 }
    4052 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
    4053 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4054 {
    4055 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
    4056 assert(varidx >= 0 && varidx < nvars);
    4057 assert(liftcoefs[varidx] == 0);
    4058
    4059 liftcoefs[varidx] = 1;
    4060 (*cutact) += solvals[varidx];
    4061 }
    4062 assert(k >= 1);
    4063 }
    4064 assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
    4065 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
    4066
    4067 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
    4068 * - finished_i[w] =
    4069 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
    4070 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
    4071 * sum_{j in Q_k} x_j <= 1
    4072 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
    4073 * - unfinished_i[w] =
    4074 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
    4075 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
    4076 * sum_{j in Q_k} x_j <= 1
    4077 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
    4078 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
    4079 */
    4080
    4081 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
    4082 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
    4083 * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
    4084 * comes from the first variable in the GUB
    4085 */
    4086 assert(ngubconsGOC1 <= ngubconsGC1);
    4087 finished[0] = 0;
    4088 for( w = 1; w <= ngubconsGOC1; w++ )
    4089 {
    4090 liftgubconsidx = gubconsGOC1[w-1];
    4091
    4092 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
    4093 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
    4094
    4095 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
    4096
    4097 assert(varidx >= 0 && varidx < nvars);
    4098 assert(liftcoefs[varidx] == 1);
    4099
    4100 min = weights[varidx];
    4101 finished[w] = finished[w-1] + min;
    4102
    4103#ifndef NDEBUG
    4104 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
    4105 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4106 {
    4107 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4108 assert(varidx >= 0 && varidx < nvars);
    4109 assert(liftcoefs[varidx] == 1);
    4110 assert(weights[varidx] >= min);
    4111 }
    4112#endif
    4113 }
    4114 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
    4115 finished[w] = SCIP_LONGINT_MAX;
    4116
    4117 /* initialize unfinished table; note that variables in GNC1 GUBs
    4118 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
    4119 * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
    4120 * comes from the first variable in the GUB
    4121 */
    4122 assert(ngubconsGNC1 <= ngubconsGC1);
    4123 unfinished[0] = 0;
    4124 for( w = 1; w <= ngubconsGNC1; w++ )
    4125 {
    4126 liftgubconsidx = gubconsGNC1[w-1];
    4127
    4128 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    4129 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
    4130
    4131 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
    4132
    4133 assert(varidx >= 0 && varidx < nvars);
    4134 assert(liftcoefs[varidx] == 1);
    4135
    4136 min = weights[varidx];
    4137 unfinished[w] = unfinished[w-1] + min;
    4138
    4139#ifndef NDEBUG
    4140 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
    4141 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4142 {
    4143 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4144 assert(varidx >= 0 && varidx < nvars);
    4145 assert(liftcoefs[varidx] == 1);
    4146 assert(weights[varidx] >= min );
    4147 }
    4148#endif
    4149 }
    4150 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
    4151 unfinished[w] = SCIP_LONGINT_MAX;
    4152
    4153 /* initialize minweights table; note that variables in GC1 GUBs
    4154 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
    4155 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
    4156 * consuming) because is it has to be build using weights from C1 only.
    4157 */
    4158 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
    4159 minweights[0] = 0;
    4160 for( w = 1; w <= ngubconsGC1; w++ )
    4161 {
    4162 liftgubconsidx = gubconsGC1[w-1];
    4163
    4164 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
    4165 || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    4166 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
    4167
    4168 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
    4169
    4170 assert(varidx >= 0 && varidx < nvars);
    4171 assert(liftcoefs[varidx] == 1);
    4172
    4173 min = weights[varidx];
    4174 minweights[w] = minweights[w-1] + min;
    4175
    4176#ifndef NDEBUG
    4177 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
    4178 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4179 {
    4180 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4181 assert(varidx >= 0 && varidx < nvars);
    4182 assert(liftcoefs[varidx] == 1);
    4183 assert(weights[varidx] >= min);
    4184 }
    4185#endif
    4186 }
    4187 minweightslen = ngubconsGC1 + 1;
    4188
    4189 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
    4190 fixedonesweight = 0;
    4191 for( j = 0; j < ngubconsGC2; j++ )
    4192 {
    4193 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
    4194
    4195 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
    4196 assert(varidx >= 0 && varidx < nvars);
    4197 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
    4198
    4199 fixedonesweight += weights[varidx];
    4200 }
    4201 assert(fixedonesweight >= 0);
    4202
    4203 /* initializes right hand side of lifted valid inequality */
    4204 *liftrhs = alpha0;
    4205
    4206 /* sequentially up-lifts all variables in GFC1 GUBs */
    4207 for( j = 0; j < ngubconsGFC1; j++ )
    4208 {
    4209 liftgubconsidx = gubconsGFC1[j];
    4210 assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
    4211
    4212 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
    4213 * compute minweight table via updated unfinished table and aleady upto date finished table;
    4214 */
    4215 k = 0;
    4216 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
    4217 {
    4218 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    4219 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
    4220 assert(ngubconsGNC1 > 0);
    4221
    4222 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
    4223 * are considered for the lifting, i.e., not capacity exceeding
    4224 */
    4225 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
    4226 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4227 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4228 assert(k >= 1);
    4229
    4230 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
    4231 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
    4232 */
    4233 weight = weights[liftgubvars[0]];
    4234
    4235 weightdiff2 = unfinished[ngubconsGNC1] - weight;
    4236 unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
    4237 for( w = ngubconsGNC1-1; w >= 1; w-- )
    4238 {
    4239 weightdiff1 = weightdiff2;
    4240 weightdiff2 = unfinished[w] - weight;
    4241
    4242 if( unfinished[w] < weightdiff1 )
    4243 unfinished[w] = weightdiff1;
    4244 else
    4245 break;
    4246 }
    4247 ngubconsGNC1--;
    4248
    4249 /* computes minweights table by combining unfished and fished tables */
    4250 computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
    4251 assert(minweights[0] == 0);
    4252 }
    4253 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
    4254 * are therefore not in the unfinished table
    4255 */
    4256 else
    4257 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
    4258
    4259#ifndef NDEBUG
    4260 nliftgubC1 = k;
    4261#endif
    4262 nliftgubvars = k;
    4263 sumliftcoef = 0;
    4264
    4265 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
    4266 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
    4267 {
    4268 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
    4269 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
    4270 {
    4271 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4272 weight = weights[liftvar];
    4273 assert(weight > 0);
    4274 assert(liftvar >= 0 && liftvar < nvars);
    4275 assert(capacity - weight >= 0);
    4276
    4277 /* put variable into array of variables in GUB that are considered for the lifting,
    4278 * i.e., not capacity exceeding
    4279 */
    4280 liftgubvars[nliftgubvars] = liftvar;
    4281 nliftgubvars++;
    4282
    4283 /* knapsack problem is infeasible:
    4284 * sets z = 0
    4285 */
    4286 if( capacity - fixedonesweight - weight < 0 )
    4287 {
    4288 z = 0;
    4289 }
    4290 /* knapsack problem is feasible:
    4291 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
    4292 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
    4293 */
    4294 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
    4295 {
    4296 z = *liftrhs;
    4297 }
    4298 /* knapsack problem is feasible:
    4299 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
    4300 */
    4301 else
    4302 {
    4303 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
    4304 left = 0;
    4305 right = (*liftrhs) + 1;
    4306 while( left < right - 1 )
    4307 {
    4308 middle = (left + right) / 2;
    4309 assert(0 <= middle && middle < minweightslen);
    4310 if( minweights[middle] <= capacity - fixedonesweight - weight )
    4311 left = middle;
    4312 else
    4313 right = middle;
    4314 }
    4315 assert(left == right - 1);
    4316 assert(0 <= left && left < minweightslen);
    4317 assert(minweights[left] <= capacity - fixedonesweight - weight);
    4318 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
    4319
    4320 /* now z = left */
    4321 z = left;
    4322 assert(z <= *liftrhs);
    4323 }
    4324
    4325 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
    4326 liftcoef = (*liftrhs) - z;
    4327 liftcoefs[liftvar] = liftcoef;
    4328 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
    4329
    4330 /* updates activity of current valid inequality */
    4331 (*cutact) += liftcoef * solvals[liftvar];
    4332
    4333 /* updates sum of all lifting coefficients in GUB */
    4334 sumliftcoef += liftcoefs[liftvar];
    4335 }
    4336 else
    4337 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
    4338 }
    4339 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
    4340 assert(nliftgubvars > nliftgubC1);
    4341
    4342 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
    4343 * and finished and minweight table can be updated easily as only C1 variables need to be considered;
    4344 * not needed for GF GUBs
    4345 */
    4346 if( sumliftcoef == 0 )
    4347 {
    4348 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
    4349 {
    4350 weight = weights[liftgubvars[0]];
    4351 /* update finished table and minweights table by applying special case of
    4352 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
    4353 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
    4354 */
    4355 for( w = minweightslen-1; w >= 1; w-- )
    4356 {
    4357 SCIP_Longint tmpval;
    4358
    4359 tmpval = safeAddMinweightsGUB(finished[w-1], weight);
    4360 finished[w] = MIN(finished[w], tmpval);
    4361
    4362 tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
    4363 minweights[w] = MIN(minweights[w], tmpval);
    4364 }
    4365 }
    4366 else
    4367 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
    4368
    4369 continue;
    4370 }
    4371
    4372 /* enlarges current minweights tables(finished, unfinished, minweights):
    4373 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
    4374 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
    4375 * and sets minweights_i[w] = infinity for
    4376 * w = |gubconsGC1| + sum_{k=1,2,..,i-1}sum_{j in Q_k} alpha_j+1,..,|C1| + sum_{k=1,2,..,i}sum_{j in Q_k} alpha_j
    4377 */
    4378 tmplen = minweightslen; /* will be updated in enlargeMinweights() */
    4379 tmpsize = minweightssize;
    4380 SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
    4381 tmplen = minweightslen;
    4382 tmpsize = minweightssize;
    4383 SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
    4384 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
    4385
    4386 /* update finished table and minweight table;
    4387 * note that instead of computing minweight table from updated finished and updated unfinished table again
    4388 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
    4389 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
    4390 * not needed because only finished table changed at this point and the change was "adding" one weight)
    4391 *
    4392 * update formular for minweight table is: minweight_i+1[w] =
    4393 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
    4394 * formular for finished table has the same pattern.
    4395 */
    4396 for( w = minweightslen-1; w >= 0; w-- )
    4397 {
    4398 SCIP_Longint minminweight;
    4399 SCIP_Longint minfinished;
    4400
    4401 for( k = 0; k < nliftgubvars; k++ )
    4402 {
    4403 liftcoef = liftcoefs[liftgubvars[k]];
    4404 weight = weights[liftgubvars[k]];
    4405
    4406 if( w < liftcoef )
    4407 {
    4408 minfinished = MIN(finished[w], weight);
    4409 minminweight = MIN(minweights[w], weight);
    4410
    4411 finished[w] = minfinished;
    4412 minweights[w] = minminweight;
    4413 }
    4414 else
    4415 {
    4416 SCIP_Longint tmpval;
    4417
    4418 assert(w >= liftcoef);
    4419
    4420 tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
    4421 minfinished = MIN(finished[w], tmpval);
    4422
    4423 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
    4424 minminweight = MIN(minweights[w], tmpval);
    4425
    4426 finished[w] = minfinished;
    4427 minweights[w] = minminweight;
    4428 }
    4429 }
    4430 }
    4431 assert(minweights[0] == 0);
    4432 }
    4433 assert(ngubconsGNC1 == 0);
    4434
    4435 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
    4436 * therefore, only work with minweight table from here on
    4437 */
    4438
    4439 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
    4440 for( j = 0; j < ngubconsGC2; j++ )
    4441 {
    4442 liftgubconsidx = gubconsGC2[j];
    4443
    4444 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
    4445 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
    4446 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
    4447 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
    4448
    4449 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
    4450 weight = weights[liftvar];
    4451
    4452 assert(liftvar >= 0 && liftvar < nvars);
    4453 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
    4454 assert(weight > 0);
    4455
    4456 /* uses binary search to find
    4457 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
    4458 */
    4459 left = 0;
    4460 right = minweightslen;
    4461 while( left < right - 1 )
    4462 {
    4463 middle = (left + right) / 2;
    4464 assert(0 <= middle && middle < minweightslen);
    4465 if( minweights[middle] <= capacity - fixedonesweight + weight )
    4466 left = middle;
    4467 else
    4468 right = middle;
    4469 }
    4470 assert(left == right - 1);
    4471 assert(0 <= left && left < minweightslen);
    4472 assert(minweights[left] <= capacity - fixedonesweight + weight);
    4473 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
    4474
    4475 /* now z = left */
    4476 z = left;
    4477 assert(z >= *liftrhs);
    4478
    4479 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
    4480 liftcoef = z - (*liftrhs);
    4481 liftcoefs[liftvar] = liftcoef;
    4482 assert(liftcoef >= 0);
    4483
    4484 /* updates sum of weights of variables fixed to one */
    4485 fixedonesweight -= weight;
    4486
    4487 /* updates right-hand side of current valid inequality */
    4488 (*liftrhs) += liftcoef;
    4489 assert(*liftrhs >= alpha0);
    4490
    4491 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
    4492 if( liftcoef == 0 )
    4493 continue;
    4494
    4495 /* updates activity of current valid inequality */
    4496 (*cutact) += liftcoef * solvals[liftvar];
    4497
    4498 /* enlarges current minweight table:
    4499 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
    4500 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
    4501 * and sets minweights_i[w] = infinity for
    4502 * w = |C1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 , ... , |C1| + sum_{k=1,2,...,i}sum_{j in Q_k} alpha_j
    4503 */
    4504 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
    4505
    4506 /* updates minweight table: minweight_i+1[w] =
    4507 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
    4508 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
    4509 */
    4510 for( w = minweightslen - 1; w >= 0; w-- )
    4511 {
    4512 if( w < liftcoef )
    4513 {
    4514 min = MIN(minweights[w], weight);
    4515 minweights[w] = min;
    4516 }
    4517 else
    4518 {
    4519 SCIP_Longint tmpval;
    4520
    4521 assert(w >= liftcoef);
    4522
    4523 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
    4524 min = MIN(minweights[w], tmpval);
    4525 minweights[w] = min;
    4526 }
    4527 }
    4528 }
    4529 assert(fixedonesweight == 0);
    4530 assert(*liftrhs >= alpha0);
    4531
    4532 /* sequentially up-lifts variables in GUB constraints in GR GUBs */
    4533 for( j = 0; j < ngubconsGR; j++ )
    4534 {
    4535 liftgubconsidx = gubconsGR[j];
    4536
    4537 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
    4538 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
    4539
    4540 sumliftcoef = 0;
    4541 nliftgubvars = 0;
    4542 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
    4543 {
    4544 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
    4545 {
    4546 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4547 weight = weights[liftvar];
    4548 assert(weight > 0);
    4549 assert(liftvar >= 0 && liftvar < nvars);
    4550 assert(capacity - weight >= 0);
    4551 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
    4552
    4553 /* put variable into array of variables in GUB that are considered for the lifting,
    4554 * i.e., not capacity exceeding
    4555 */
    4556 liftgubvars[nliftgubvars] = liftvar;
    4557 nliftgubvars++;
    4558
    4559 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
    4560 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
    4561 */
    4562 if( minweights[*liftrhs] <= capacity - weight )
    4563 {
    4564 z = *liftrhs;
    4565 }
    4566 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
    4567 */
    4568 else
    4569 {
    4570 left = 0;
    4571 right = (*liftrhs) + 1;
    4572 while( left < right - 1 )
    4573 {
    4574 middle = (left + right) / 2;
    4575 assert(0 <= middle && middle < minweightslen);
    4576 if( minweights[middle] <= capacity - weight )
    4577 left = middle;
    4578 else
    4579 right = middle;
    4580 }
    4581 assert(left == right - 1);
    4582 assert(0 <= left && left < minweightslen);
    4583 assert(minweights[left] <= capacity - weight);
    4584 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
    4585
    4586 /* now z = left */
    4587 z = left;
    4588 assert(z <= *liftrhs);
    4589 }
    4590 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
    4591 liftcoef = (*liftrhs) - z;
    4592 liftcoefs[liftvar] = liftcoef;
    4593 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
    4594
    4595 /* updates activity of current valid inequality */
    4596 (*cutact) += liftcoef * solvals[liftvar];
    4597
    4598 /* updates sum of all lifting coefficients in GUB */
    4599 sumliftcoef += liftcoefs[liftvar];
    4600 }
    4601 else
    4602 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
    4603 }
    4604 assert(nliftgubvars >= 1); /* at least one variable is in R */
    4605
    4606 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
    4607 if( sumliftcoef == 0 )
    4608 continue;
    4609
    4610 /* updates minweight table: minweight_i+1[w] =
    4611 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
    4612 */
    4613 for( w = *liftrhs; w >= 0; w-- )
    4614 {
    4615 for( k = 0; k < nliftgubvars; k++ )
    4616 {
    4617 liftcoef = liftcoefs[liftgubvars[k]];
    4618 weight = weights[liftgubvars[k]];
    4619
    4620 if( w < liftcoef )
    4621 {
    4622 min = MIN(minweights[w], weight);
    4623 minweights[w] = min;
    4624 }
    4625 else
    4626 {
    4627 SCIP_Longint tmpval;
    4628
    4629 assert(w >= liftcoef);
    4630
    4631 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
    4632 min = MIN(minweights[w], tmpval);
    4633 minweights[w] = min;
    4634 }
    4635 }
    4636 }
    4637 assert(minweights[0] == 0);
    4638 }
    4639
    4640 /* frees temporary memory */
    4641 SCIPfreeBufferArray(scip, &minweights);
    4642 SCIPfreeBufferArray(scip, &finished);
    4643 SCIPfreeBufferArray(scip, &unfinished);
    4644 SCIPfreeBufferArray(scip, &liftgubvars);
    4645 SCIPfreeBufferArray(scip, &gubconsGOC1 );
    4646 SCIPfreeBufferArray(scip, &gubconsGNC1);
    4647
    4648 return SCIP_OKAY;
    4649}
    4650
    4651/** lifts given minimal cover inequality
    4652 * \f[
    4653 * \sum_{j \in C} x_j \leq |C| - 1
    4654 * \f]
    4655 * valid for
    4656 * \f[
    4657 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
    4658 * \f]
    4659 * to a valid inequality
    4660 * \f[
    4661 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
    4662 * \f]
    4663 * for
    4664 * \f[
    4665 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
    4666 * \f]
    4667 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
    4668 */
    4669static
    4671 SCIP* scip, /**< SCIP data structure */
    4672 SCIP_VAR** vars, /**< variables in knapsack constraint */
    4673 int nvars, /**< number of variables in knapsack constraint */
    4674 int ntightened, /**< number of variables with tightened upper bound */
    4675 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    4676 SCIP_Longint capacity, /**< capacity of knapsack */
    4677 SCIP_Real* solvals, /**< solution values of all problem variables */
    4678 int* covervars, /**< cover variables */
    4679 int* noncovervars, /**< noncover variables */
    4680 int ncovervars, /**< number of cover variables */
    4681 int nnoncovervars, /**< number of noncover variables */
    4682 SCIP_Longint coverweight, /**< weight of cover */
    4683 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
    4684 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
    4685 )
    4686{
    4687 SCIP_Longint* maxweightsums;
    4688 SCIP_Longint* intervalends;
    4689 SCIP_Longint* rhos;
    4690 SCIP_Real* sortkeys;
    4691 SCIP_Longint lambda;
    4692 int j;
    4693 int h;
    4694
    4695 assert(scip != NULL);
    4696 assert(vars != NULL);
    4697 assert(nvars >= 0);
    4698 assert(weights != NULL);
    4699 assert(capacity >= 0);
    4700 assert(solvals != NULL);
    4701 assert(covervars != NULL);
    4702 assert(noncovervars != NULL);
    4703 assert(ncovervars > 0 && ncovervars <= nvars);
    4704 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
    4705 assert(ncovervars + nnoncovervars == nvars - ntightened);
    4706 assert(liftcoefs != NULL);
    4707 assert(cutact != NULL);
    4708
    4709 /* allocates temporary memory */
    4710 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
    4711 SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
    4712 SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
    4713 SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
    4714
    4715 /* initializes data structures */
    4716 BMSclearMemoryArray(liftcoefs, nvars);
    4717 *cutact = 0.0;
    4718
    4719 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
    4720 * and calculates activity of current valid inequality
    4721 */
    4722 for( j = 0; j < ncovervars; j++ )
    4723 {
    4724 assert(liftcoefs[covervars[j]] == 0.0);
    4725 liftcoefs[covervars[j]] = 1.0;
    4726 sortkeys[j] = (SCIP_Real) weights[covervars[j]];
    4727 (*cutact) += solvals[covervars[j]];
    4728 }
    4729 SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
    4730
    4731 /* calculates weight excess of cover C */
    4732 lambda = coverweight - capacity;
    4733 assert(lambda > 0);
    4734
    4735 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
    4736 maxweightsums[0] = 0;
    4737 for( h = 1; h <= ncovervars; h++ )
    4738 {
    4739 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
    4740 intervalends[h-1] = maxweightsums[h] - lambda;
    4741 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
    4742 }
    4743
    4744 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
    4745 for( j = 0; j < nnoncovervars; j++ )
    4746 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
    4747 SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
    4748
    4749 /* calculates lifting coefficient for all variables in N\C */
    4750 h = 0;
    4751 for( j = 0; j < nnoncovervars; j++ )
    4752 {
    4753 int liftvar;
    4754 SCIP_Longint weight;
    4755 SCIP_Real liftcoef;
    4756
    4757 liftvar = noncovervars[j];
    4758 weight = weights[liftvar];
    4759
    4760 while( intervalends[h] < weight )
    4761 h++;
    4762
    4763 if( h == 0 )
    4764 liftcoef = h;
    4765 else
    4766 {
    4767 if( weight <= intervalends[h-1] + rhos[h] )
    4768 {
    4769 SCIP_Real tmp1;
    4770 SCIP_Real tmp2;
    4771 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
    4772 tmp2 = (SCIP_Real) rhos[1];
    4773 liftcoef = h - ( tmp1 / tmp2 );
    4774 }
    4775 else
    4776 liftcoef = h;
    4777 }
    4778
    4779 /* sets lifting coefficient */
    4780 assert(liftcoefs[liftvar] == 0.0);
    4781 liftcoefs[liftvar] = liftcoef;
    4782
    4783 /* updates activity of current valid inequality */
    4784 (*cutact) += liftcoef * solvals[liftvar];
    4785 }
    4786
    4787 /* frees temporary memory */
    4788 SCIPfreeBufferArray(scip, &rhos);
    4789 SCIPfreeBufferArray(scip, &intervalends);
    4790 SCIPfreeBufferArray(scip, &maxweightsums);
    4791 SCIPfreeBufferArray(scip, &sortkeys);
    4792
    4793 return SCIP_OKAY;
    4794}
    4795
    4796
    4797/** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
    4798 * given knapsack problem
    4799*/
    4800static
    4802 SCIP* scip, /**< SCIP data structure */
    4803 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
    4804 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    4805 SCIP_VAR** vars, /**< variables in knapsack constraint */
    4806 int nvars, /**< number of variables in knapsack constraint */
    4807 int ntightened, /**< number of variables with tightened upper bound */
    4808 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    4809 SCIP_Longint capacity, /**< capacity of knapsack */
    4810 SCIP_Real* solvals, /**< solution values of all problem variables */
    4811 int* mincovervars, /**< mincover variables */
    4812 int* nonmincovervars, /**< nonmincover variables */
    4813 int nmincovervars, /**< number of mincover variables */
    4814 int nnonmincovervars, /**< number of nonmincover variables */
    4815 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    4816 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
    4817 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
    4818 int* ncuts /**< pointer to add up the number of found cuts */
    4819 )
    4820{
    4821 int* varsC1;
    4822 int* varsC2;
    4823 int* varsF;
    4824 int* varsR;
    4825 int nvarsC1;
    4826 int nvarsC2;
    4827 int nvarsF;
    4828 int nvarsR;
    4829 SCIP_Real cutact;
    4830 int* liftcoefs;
    4831 int liftrhs;
    4832
    4833 assert( cutoff != NULL );
    4834 *cutoff = FALSE;
    4835
    4836 /* allocates temporary memory */
    4841 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
    4842
    4843 /* gets partition (C_1,C_2) of C, i.e. C_1 & C_2 = C and C_1 cap C_2 = emptyset, with C_1 not empty; chooses partition
    4844 * as follows
    4845 * C_2 = { j in C : x*_j = 1 } and
    4846 * C_1 = C\C_2
    4847 */
    4848 getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
    4849 assert(nvarsC1 + nvarsC2 == nmincovervars);
    4850 assert(nmincovervars > 0);
    4851 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
    4852
    4853 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
    4854 if( nvarsC1 < 2 && nvarsC2 > 0)
    4855 {
    4856 SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
    4857 assert(nvarsC1 >= 1);
    4858 }
    4859 assert(nvarsC2 == 0 || nvarsC1 >= 1);
    4860
    4861 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
    4862 * R = { j in N\C : x*_j = 0 } and
    4863 * F = (N\C)\F
    4864 */
    4865 getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
    4866 assert(nvarsF + nvarsR == nnonmincovervars);
    4867 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
    4868
    4869 /* lift cuts without GUB information */
    4870 if( gubset == NULL )
    4871 {
    4872 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
    4873 * lifting procedure
    4874 */
    4875 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
    4876
    4877 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
    4878 *
    4879 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j }
    4880 *
    4881 * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
    4882 *
    4883 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
    4884 *
    4885 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
    4886 * up-lifting for the variables in R according to the second level lifting sequence
    4887 */
    4888 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
    4889 varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
    4890 }
    4891 /* lift cuts with GUB information */
    4892 else
    4893 {
    4894 int* gubconsGC1;
    4895 int* gubconsGC2;
    4896 int* gubconsGFC1;
    4897 int* gubconsGR;
    4898 int ngubconsGC1;
    4899 int ngubconsGC2;
    4900 int ngubconsGFC1;
    4901 int ngubconsGR;
    4902 int ngubconss;
    4903 int nconstightened;
    4904 int maxgubvarssize;
    4905
    4906 assert(nvars == gubset->nvars);
    4907
    4908 ngubconsGC1 = 0;
    4909 ngubconsGC2 = 0;
    4910 ngubconsGFC1 = 0;
    4911 ngubconsGR = 0;
    4912 ngubconss = gubset->ngubconss;
    4913 nconstightened = 0;
    4914 maxgubvarssize = 0;
    4915
    4916 /* allocates temporary memory */
    4917 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
    4918 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
    4919 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
    4921
    4922 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
    4923 * the GUBs for the sequential GUB wise lifting procedure
    4924 */
    4925 SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
    4926 nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
    4927 &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
    4928
    4929 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
    4930 *
    4931 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j,
    4932 * sum_{j in Q_i} x_j <= 1, forall i in I }
    4933 *
    4934 * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
    4935 *
    4936 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0, sum_{j in Q_i} x_j <= 1, forall i in I },
    4937 *
    4938 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
    4939 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
    4940 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
    4941 */
    4942 SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
    4943 gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
    4944 MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
    4945
    4946 /* frees temporary memory */
    4947 SCIPfreeBufferArray(scip, &gubconsGR);
    4948 SCIPfreeBufferArray(scip, &gubconsGFC1);
    4949 SCIPfreeBufferArray(scip, &gubconsGC2);
    4950 SCIPfreeBufferArray(scip, &gubconsGC1);
    4951 }
    4952
    4953 /* checks if lifting yielded a violated cut */
    4954 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
    4955 {
    4956 SCIP_ROW* row;
    4957 char name[SCIP_MAXSTRLEN];
    4958 int j;
    4959
    4960 /* creates LP row */
    4961 assert( cons == NULL || sepa == NULL );
    4962 if ( cons != NULL )
    4963 {
    4965 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
    4966 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
    4967 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
    4968 }
    4969 else if ( sepa != NULL )
    4970 {
    4971 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
    4972 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
    4973 }
    4974 else
    4975 {
    4976 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
    4978 }
    4979
    4980 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
    4982 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
    4983 for( j = 0; j < nvarsC1; j++ )
    4984 {
    4985 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
    4986 }
    4987 for( j = 0; j < nvarsC2; j++ )
    4988 {
    4989 if( liftcoefs[varsC2[j]] > 0 )
    4990 {
    4991 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
    4992 }
    4993 }
    4994 for( j = 0; j < nvarsF; j++ )
    4995 {
    4996 if( liftcoefs[varsF[j]] > 0 )
    4997 {
    4998 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
    4999 }
    5000 }
    5001 for( j = 0; j < nvarsR; j++ )
    5002 {
    5003 if( liftcoefs[varsR[j]] > 0 )
    5004 {
    5005 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
    5006 }
    5007 }
    5009
    5010 /* checks if cut is violated enough */
    5011 if( SCIPisCutEfficacious(scip, sol, row) )
    5012 {
    5013 if( cons != NULL )
    5014 {
    5016 }
    5017 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    5018 (*ncuts)++;
    5019 }
    5020 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    5021 }
    5022
    5023 /* frees temporary memory */
    5024 SCIPfreeBufferArray(scip, &liftcoefs);
    5025 SCIPfreeBufferArray(scip, &varsR);
    5026 SCIPfreeBufferArray(scip, &varsF);
    5027 SCIPfreeBufferArray(scip, &varsC2);
    5028 SCIPfreeBufferArray(scip, &varsC1);
    5029
    5030 return SCIP_OKAY;
    5031}
    5032
    5033/** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
    5034static
    5036 SCIP* scip, /**< SCIP data structure */
    5037 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
    5038 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5039 SCIP_VAR** vars, /**< variables in knapsack constraint */
    5040 int nvars, /**< number of variables in knapsack constraint */
    5041 int ntightened, /**< number of variables with tightened upper bound */
    5042 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5043 SCIP_Longint capacity, /**< capacity of knapsack */
    5044 SCIP_Real* solvals, /**< solution values of all problem variables */
    5045 int* feassetvars, /**< variables in feasible set */
    5046 int* nonfeassetvars, /**< variables not in feasible set */
    5047 int nfeassetvars, /**< number of variables in feasible set */
    5048 int nnonfeassetvars, /**< number of variables not in feasible set */
    5049 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    5050 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    5051 int* ncuts /**< pointer to add up the number of found cuts */
    5052 )
    5053{
    5054 int* varsT1;
    5055 int* varsT2;
    5056 int* varsF;
    5057 int* varsR;
    5058 int* liftcoefs;
    5059 SCIP_Real cutact;
    5060 int nvarsT1;
    5061 int nvarsT2;
    5062 int nvarsF;
    5063 int nvarsR;
    5064 int liftrhs;
    5065 int j;
    5066
    5067 assert( cutoff != NULL );
    5068 *cutoff = FALSE;
    5069
    5070 /* allocates temporary memory */
    5075 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
    5076
    5077 /* gets partition (T_1,T_2) of T, i.e. T_1 & T_2 = T and T_1 cap T_2 = emptyset, with T_1 not empty; chooses partition
    5078 * as follows
    5079 * T_2 = { j in T : x*_j = 1 } and
    5080 * T_1 = T\T_2
    5081 */
    5082 getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
    5083 assert(nvarsT1 + nvarsT2 == nfeassetvars);
    5084
    5085 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
    5086 if( nvarsT1 == 0 && nvarsT2 > 0)
    5087 {
    5088 SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
    5089 assert(nvarsT1 == 1);
    5090 }
    5091 assert(nvarsT2 == 0 || nvarsT1 > 0);
    5092
    5093 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
    5094 * R = { j in N\T : x*_j = 0 } and
    5095 * F = (N\T)\F
    5096 */
    5097 getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
    5098 assert(nvarsF + nvarsR == nnonfeassetvars);
    5099 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
    5100
    5101 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
    5102 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
    5103 * is included in the sorting routine)
    5104 */
    5105 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
    5106
    5107 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
    5108 *
    5109 * S^0 = { x in {0,1}^|T_1| : sum_{j in T_1} a_j x_j <= a_0 - sum_{j in T_2} a_j }
    5110 *
    5111 * to a valid inequality sum_{j in T_1} x_j + sum_{j in N\T_1} alpha_j x_j <= |T_1| + sum_{j in T_2} alpha_j for
    5112 *
    5113 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
    5114 *
    5115 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
    5116 * up-lifting for the variabels in R according to the second level lifting sequence
    5117 */
    5118 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
    5119 nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
    5120
    5121 /* checks if lifting yielded a violated cut */
    5122 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
    5123 {
    5124 SCIP_ROW* row;
    5125 char name[SCIP_MAXSTRLEN];
    5126
    5127 /* creates LP row */
    5128 assert( cons == NULL || sepa == NULL );
    5129 if( cons != NULL )
    5130 {
    5133 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
    5134 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
    5135 }
    5136 else if ( sepa != NULL )
    5137 {
    5138 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
    5139 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
    5140 }
    5141 else
    5142 {
    5143 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
    5145 }
    5146
    5147 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
    5149 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
    5150 for( j = 0; j < nvarsT1; j++ )
    5151 {
    5152 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
    5153 }
    5154 for( j = 0; j < nvarsT2; j++ )
    5155 {
    5156 if( liftcoefs[varsT2[j]] > 0 )
    5157 {
    5158 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
    5159 }
    5160 }
    5161 for( j = 0; j < nvarsF; j++ )
    5162 {
    5163 if( liftcoefs[varsF[j]] > 0 )
    5164 {
    5165 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
    5166 }
    5167 }
    5168 for( j = 0; j < nvarsR; j++ )
    5169 {
    5170 if( liftcoefs[varsR[j]] > 0 )
    5171 {
    5172 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
    5173 }
    5174 }
    5176
    5177 /* checks if cut is violated enough */
    5178 if( SCIPisCutEfficacious(scip, sol, row) )
    5179 {
    5180 if( cons != NULL )
    5181 {
    5183 }
    5184 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    5185 (*ncuts)++;
    5186 }
    5187 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    5188 }
    5189
    5190 /* frees temporary memory */
    5191 SCIPfreeBufferArray(scip, &liftcoefs);
    5192 SCIPfreeBufferArray(scip, &varsR);
    5193 SCIPfreeBufferArray(scip, &varsF);
    5194 SCIPfreeBufferArray(scip, &varsT2);
    5195 SCIPfreeBufferArray(scip, &varsT1);
    5196
    5197 return SCIP_OKAY;
    5198}
    5199
    5200/** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
    5201static
    5203 SCIP* scip, /**< SCIP data structure */
    5204 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
    5205 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5206 SCIP_VAR** vars, /**< variables in knapsack constraint */
    5207 int nvars, /**< number of variables in knapsack constraint */
    5208 int ntightened, /**< number of variables with tightened upper bound */
    5209 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5210 SCIP_Longint capacity, /**< capacity of knapsack */
    5211 SCIP_Real* solvals, /**< solution values of all problem variables */
    5212 int* mincovervars, /**< mincover variables */
    5213 int* nonmincovervars, /**< nonmincover variables */
    5214 int nmincovervars, /**< number of mincover variables */
    5215 int nnonmincovervars, /**< number of nonmincover variables */
    5216 SCIP_Longint mincoverweight, /**< weight of minimal cover */
    5217 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    5218 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    5219 int* ncuts /**< pointer to add up the number of found cuts */
    5220 )
    5221{
    5222 SCIP_Real* realliftcoefs;
    5223 SCIP_Real cutact;
    5224 int liftrhs;
    5225
    5226 assert( cutoff != NULL );
    5227 *cutoff = FALSE;
    5228 cutact = 0.0;
    5229
    5230 /* allocates temporary memory */
    5231 SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
    5232
    5233 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
    5234 *
    5235 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
    5236 *
    5237 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
    5238 *
    5239 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
    5240 *
    5241 * uses superadditive up-lifting for the variables in N\C.
    5242 */
    5243 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
    5244 nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
    5245 liftrhs = nmincovervars - 1;
    5246
    5247 /* checks if lifting yielded a violated cut */
    5248 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
    5249 {
    5250 SCIP_ROW* row;
    5251 char name[SCIP_MAXSTRLEN];
    5252 int j;
    5253
    5254 /* creates LP row */
    5255 assert( cons == NULL || sepa == NULL );
    5256 if ( cons != NULL )
    5257 {
    5260 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
    5261 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
    5262 }
    5263 else if ( sepa != NULL )
    5264 {
    5265 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
    5266 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
    5267 }
    5268 else
    5269 {
    5270 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
    5272 }
    5273
    5274 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
    5276 assert(nmincovervars + nnonmincovervars == nvars - ntightened);
    5277 for( j = 0; j < nmincovervars; j++ )
    5278 {
    5279 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
    5280 }
    5281 for( j = 0; j < nnonmincovervars; j++ )
    5282 {
    5283 assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
    5284 if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
    5285 {
    5286 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
    5287 }
    5288 }
    5290
    5291 /* checks if cut is violated enough */
    5292 if( SCIPisCutEfficacious(scip, sol, row) )
    5293 {
    5294 if( cons != NULL )
    5295 {
    5297 }
    5298 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    5299 (*ncuts)++;
    5300 }
    5301 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    5302 }
    5303
    5304 /* frees temporary memory */
    5305 SCIPfreeBufferArray(scip, &realliftcoefs);
    5306
    5307 return SCIP_OKAY;
    5308}
    5309
    5310/** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
    5311 * to be in C, i.e. in the order of non-increasing (1 - x*_j)/a_j, if the transformed separation problem was used to find
    5312 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
    5313 * note that all variables with x*_j = 1 will be removed last
    5314 */
    5315static
    5317 SCIP* scip, /**< SCIP data structure */
    5318 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5319 SCIP_Longint capacity, /**< capacity of knapsack */
    5320 SCIP_Real* solvals, /**< solution values of all problem variables */
    5321 int* covervars, /**< pointer to store cover variables */
    5322 int* noncovervars, /**< pointer to store noncover variables */
    5323 int* ncovervars, /**< pointer to store number of cover variables */
    5324 int* nnoncovervars, /**< pointer to store number of noncover variables */
    5325 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
    5326 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
    5327 )
    5328{
    5329 SORTKEYPAIR** sortkeypairs;
    5330 SORTKEYPAIR** sortkeypairssorted;
    5331 SCIP_Longint minweight;
    5332 int nsortkeypairs;
    5333 int minweightidx;
    5334 int j;
    5335 int k;
    5336
    5337 assert(scip != NULL);
    5338 assert(covervars != NULL);
    5339 assert(noncovervars != NULL);
    5340 assert(ncovervars != NULL);
    5341 assert(*ncovervars > 0);
    5342 assert(nnoncovervars != NULL);
    5343 assert(*nnoncovervars >= 0);
    5344 assert(coverweight != NULL);
    5345 assert(*coverweight > 0);
    5346 assert(*coverweight > capacity);
    5347
    5348 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
    5349 * order */
    5350 nsortkeypairs = *ncovervars;
    5351 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
    5352 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
    5353
    5354 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
    5355 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
    5356 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
    5357 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
    5358 */
    5359 assert(*ncovervars == nsortkeypairs);
    5360 if( modtransused )
    5361 {
    5362 for( j = 0; j < *ncovervars; j++ )
    5363 {
    5364 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
    5365 sortkeypairssorted[j] = sortkeypairs[j];
    5366
    5367 sortkeypairs[j]->key1 = solvals[covervars[j]];
    5368 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
    5369 }
    5370 }
    5371 else
    5372 {
    5373 for( j = 0; j < *ncovervars; j++ )
    5374 {
    5375 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
    5376 sortkeypairssorted[j] = sortkeypairs[j];
    5377
    5378 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
    5379 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
    5380 }
    5381 }
    5382 SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
    5383
    5384 /* gets j' with a_j' = min{ a_j : j in C } */
    5385 minweightidx = 0;
    5386 minweight = weights[covervars[minweightidx]];
    5387 for( j = 1; j < *ncovervars; j++ )
    5388 {
    5389 if( weights[covervars[j]] <= minweight )
    5390 {
    5391 minweightidx = j;
    5392 minweight = weights[covervars[minweightidx]];
    5393 }
    5394 }
    5395 assert(minweightidx >= 0 && minweightidx < *ncovervars);
    5396 assert(minweight > 0 && minweight <= *coverweight);
    5397
    5398 j = 0;
    5399 /* removes variables from C until the remaining variables form a minimal cover */
    5400 while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
    5401 {
    5402 assert(minweightidx >= j);
    5403 assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
    5404
    5405 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
    5406 if( (*coverweight) - weights[covervars[j]] <= capacity )
    5407 {
    5408 ++j;
    5409 continue;
    5410 }
    5411
    5412 /* adds j to N\C */
    5413 noncovervars[*nnoncovervars] = covervars[j];
    5414 (*nnoncovervars)++;
    5415
    5416 /* removes j from C */
    5417 (*coverweight) -= weights[covervars[j]];
    5418 for( k = j; k < (*ncovervars) - 1; k++ )
    5419 covervars[k] = covervars[k+1];
    5420 (*ncovervars)--;
    5421
    5422 /* updates j' with a_j' = min{ a_j : j in C } */
    5423 if( j == minweightidx )
    5424 {
    5425 minweightidx = 0;
    5426 minweight = weights[covervars[minweightidx]];
    5427 for( k = 1; k < *ncovervars; k++ )
    5428 {
    5429 if( weights[covervars[k]] <= minweight )
    5430 {
    5431 minweightidx = k;
    5432 minweight = weights[covervars[minweightidx]];
    5433 }
    5434 }
    5435 assert(minweight > 0 && minweight <= *coverweight);
    5436 assert(minweightidx >= 0 && minweightidx < *ncovervars);
    5437 }
    5438 else
    5439 {
    5440 assert(minweightidx > j);
    5441 minweightidx--;
    5442 }
    5443 /* j needs to stay the same */
    5444 }
    5445 assert((*coverweight) > capacity);
    5446 assert((*coverweight) - minweight <= capacity);
    5447
    5448 /* frees temporary memory */
    5449 for( j = nsortkeypairs-1; j >= 0; j-- )
    5450 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
    5451 SCIPfreeBufferArray(scip, &sortkeypairssorted);
    5452 SCIPfreeBufferArray(scip, &sortkeypairs);
    5453
    5454 return SCIP_OKAY;
    5455}
    5456
    5457/** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
    5458 * they were chosen to be in C_init:
    5459 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
    5460 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
    5461 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
    5462 * and all subsequent feasible sets.
    5463 */
    5464static
    5466 SCIP* scip, /**< SCIP data structure */
    5467 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
    5468 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5469 SCIP_VAR** vars, /**< variables in knapsack constraint */
    5470 int nvars, /**< number of variables in knapsack constraint */
    5471 int ntightened, /**< number of variables with tightened upper bound */
    5472 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5473 SCIP_Longint capacity, /**< capacity of knapsack */
    5474 SCIP_Real* solvals, /**< solution values of all problem variables */
    5475 int* covervars, /**< pointer to store cover variables */
    5476 int* noncovervars, /**< pointer to store noncover variables */
    5477 int* ncovervars, /**< pointer to store number of cover variables */
    5478 int* nnoncovervars, /**< pointer to store number of noncover variables */
    5479 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
    5480 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
    5481 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    5482 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    5483 int* ncuts /**< pointer to add up the number of found cuts */
    5484 )
    5485{
    5486 SCIP_Real* sortkeys;
    5487 int j;
    5488 int k;
    5489
    5490 assert(scip != NULL);
    5491 assert(covervars != NULL);
    5492 assert(noncovervars != NULL);
    5493 assert(ncovervars != NULL);
    5494 assert(*ncovervars > 0);
    5495 assert(nnoncovervars != NULL);
    5496 assert(*nnoncovervars >= 0);
    5497 assert(coverweight != NULL);
    5498 assert(*coverweight > 0);
    5499 assert(*coverweight > capacity);
    5500 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
    5501 assert(cutoff != NULL);
    5502
    5503 *cutoff = FALSE;
    5504
    5505 /* allocates temporary memory */
    5506 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
    5507
    5508 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
    5509 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
    5510 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
    5511 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
    5512 */
    5513 if( modtransused )
    5514 {
    5515 for( j = 0; j < *ncovervars; j++ )
    5516 {
    5517 sortkeys[j] = solvals[covervars[j]];
    5518 assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
    5519 }
    5520 }
    5521 else
    5522 {
    5523 for( j = 0; j < *ncovervars; j++ )
    5524 {
    5525 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
    5526 assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
    5527 }
    5528 }
    5529 SCIPsortRealInt(sortkeys, covervars, *ncovervars);
    5530
    5531 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
    5532 * in addition to an extended weight inequality this gives cardinality inequalities */
    5533 while( *ncovervars >= 2 )
    5534 {
    5535 /* adds first element of C_init to N\C_init */
    5536 noncovervars[*nnoncovervars] = covervars[0];
    5537 (*nnoncovervars)++;
    5538
    5539 /* removes first element from C_init */
    5540 (*coverweight) -= weights[covervars[0]];
    5541 for( k = 0; k < (*ncovervars) - 1; k++ )
    5542 covervars[k] = covervars[k+1];
    5543 (*ncovervars)--;
    5544
    5545 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
    5546 if( (*coverweight) <= capacity )
    5547 {
    5548 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
    5549 covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
    5550 }
    5551
    5552 /* stop if cover is too large */
    5553 if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
    5554 break;
    5555 }
    5556
    5557 /* frees temporary memory */
    5558 SCIPfreeBufferArray(scip, &sortkeys);
    5559
    5560 return SCIP_OKAY;
    5561}
    5562
    5563/** separates different classes of valid inequalities for the 0-1 knapsack problem */
    5565 SCIP* scip, /**< SCIP data structure */
    5566 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
    5567 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5568 SCIP_VAR** vars, /**< variables in knapsack constraint */
    5569 int nvars, /**< number of variables in knapsack constraint */
    5570 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5571 SCIP_Longint capacity, /**< capacity of knapsack */
    5572 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    5573 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
    5574 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
    5575 int* ncuts /**< pointer to add up the number of found cuts */
    5576 )
    5577{
    5578 SCIP_Real* solvals;
    5579 int* covervars;
    5580 int* noncovervars;
    5581 SCIP_Bool coverfound;
    5582 SCIP_Bool fractional;
    5583 SCIP_Bool modtransused;
    5584 SCIP_Longint coverweight;
    5585 int ncovervars;
    5586 int nnoncovervars;
    5587 int ntightened;
    5588
    5589 assert(scip != NULL);
    5590 assert(capacity >= 0);
    5591 assert(cutoff != NULL);
    5592 assert(ncuts != NULL);
    5593
    5594 *cutoff = FALSE;
    5595
    5596 if( nvars == 0 )
    5597 return SCIP_OKAY;
    5598
    5599 assert(vars != NULL);
    5600 assert(nvars > 0);
    5601 assert(weights != NULL);
    5602
    5603 /* increase age of constraint (age is reset to zero, if a cut was found) */
    5604 if( cons != NULL )
    5605 {
    5606 SCIP_CALL( SCIPincConsAge(scip, cons) );
    5607 }
    5608
    5609 /* allocates temporary memory */
    5611 SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
    5612 SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
    5613
    5614 /* gets solution values of all problem variables */
    5615 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
    5616
    5617#ifdef SCIP_DEBUG
    5618 {
    5619 int i;
    5620
    5621 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
    5622 cons == NULL ? "-" : SCIPconsGetName(cons));
    5623 for( i = 0; i < nvars; ++i )
    5624 {
    5625 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
    5626 }
    5627 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
    5628 }
    5629#endif
    5630
    5631 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
    5632 */
    5633 if( usegubs )
    5634 {
    5635 SCIP_GUBSET* gubset;
    5636
    5637 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
    5638
    5639 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
    5640 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
    5641
    5642 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
    5643 SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
    5644 assert(gubset->ngubconss <= nvars);
    5645
    5646 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
    5647 * MODIFIED transformed separation problem and taking into account the following fixing:
    5648 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
    5649 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
    5650 * if one exists
    5651 */
    5652 modtransused = TRUE;
    5653 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5654 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
    5655
    5656 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
    5657
    5658 /* if x* is not fractional we stop the separation routine */
    5659 if( !fractional )
    5660 {
    5661 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
    5662
    5663 /* frees memory for GUB set data structure */
    5664 GUBsetFree(scip, &gubset);
    5665
    5666 goto TERMINATE;
    5667 }
    5668
    5669 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
    5670 if( coverfound )
    5671 {
    5672 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
    5673 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
    5674 */
    5675 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5676 &nnoncovervars, &coverweight, modtransused) );
    5677
    5678 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
    5679 if( gubset->ngubconss < nvars )
    5680 {
    5681 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
    5682 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
    5683 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
    5684 }
    5685 else
    5686 {
    5687 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
    5688 * GUB information
    5689 */
    5690 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
    5691 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
    5692 }
    5693 }
    5694
    5695 /* frees memory for GUB set data structure */
    5696 GUBsetFree(scip, &gubset);
    5697 }
    5698 else
    5699 {
    5700 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
    5701 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
    5702 */
    5703
    5704 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
    5705 * MODIFIED transformed separation problem and taking into account the following fixing:
    5706 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
    5707 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
    5708 * if one exists
    5709 */
    5710 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
    5711 modtransused = TRUE;
    5712 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5713 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
    5714 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
    5715
    5716 /* if x* is not fractional we stop the separation routine */
    5717 if( !fractional )
    5718 goto TERMINATE;
    5719
    5720 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
    5721 if( coverfound )
    5722 {
    5723 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
    5724 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
    5725 */
    5726 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5727 &nnoncovervars, &coverweight, modtransused) );
    5728
    5729 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
    5730 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
    5731 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
    5732
    5733 if( USESUPADDLIFT ) /*lint !e506 !e774*/
    5734 {
    5735 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
    5736 /* separates lifted minimal cover inequalities using superadditive up-lifting */
    5737 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
    5738 solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
    5739 }
    5740 }
    5741 }
    5742
    5743 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
    5744 if ( ! (*cutoff) )
    5745 {
    5746 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
    5747 * transformed separation problem and taking into account the following fixing:
    5748 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
    5749 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
    5750 * if one exists
    5751 */
    5752 SCIPdebugMsg(scip, "separate LEWI cuts:\n");
    5753 modtransused = FALSE;
    5754 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5755 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
    5756 assert(fractional);
    5757 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
    5758
    5759 /* if no cover was found we stop the separation routine */
    5760 if( coverfound )
    5761 {
    5762 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
    5763 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
    5764 * up- and down-lifting for this feasible set and all subsequent feasible sets.
    5765 */
    5766 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
    5767 &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
    5768 }
    5769 }
    5770
    5771 TERMINATE:
    5772 /* frees temporary memory */
    5773 SCIPfreeBufferArray(scip, &noncovervars);
    5774 SCIPfreeBufferArray(scip, &covervars);
    5775 SCIPfreeBufferArray(scip, &solvals);
    5776
    5777 return SCIP_OKAY;
    5778}
    5779
    5780/* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
    5782 SCIP* scip, /**< SCIP data structure */
    5783 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
    5784 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5785 int nknapvars, /**< number of variables in the continuous knapsack constraint */
    5786 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
    5787 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
    5788 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
    5789 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
    5790 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    5791 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
    5792 int* ncuts /**< pointer to add up the number of found cuts */
    5793 )
    5794{
    5795 SCIP_VAR** binvars;
    5796 SCIP_VAR** consvars;
    5797 SCIP_Real* binvals;
    5798 SCIP_Longint* consvals;
    5799 SCIP_Longint minact;
    5800 SCIP_Longint maxact;
    5801 SCIP_Real intscalar;
    5802 SCIP_Bool success;
    5803 int nbinvars;
    5804 int nconsvars;
    5805 int i;
    5806
    5807 int* tmpindices;
    5808 int tmp;
    5809 SCIP_CONSHDLR* conshdlr;
    5810 SCIP_CONSHDLRDATA* conshdlrdata;
    5811 SCIP_Bool noknapsackconshdlr;
    5812 SCIP_Bool usegubs;
    5813
    5814 assert(nknapvars > 0);
    5815 assert(knapvars != NULL);
    5816 assert(cutoff != NULL);
    5817
    5818 tmpindices = NULL;
    5819
    5820 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
    5821 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
    5822
    5823 binvars = SCIPgetVars(scip);
    5824
    5825 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
    5826 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    5827
    5828 *cutoff = FALSE;
    5829
    5830 if( nbinvars == 0 )
    5831 return SCIP_OKAY;
    5832
    5833 /* set up data structures */
    5834 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
    5835 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
    5836
    5837 /* get conshdlrdata to use cleared memory */
    5838 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    5839 if( conshdlr == NULL )
    5840 {
    5841 noknapsackconshdlr = TRUE;
    5842 usegubs = DEFAULT_USEGUBS;
    5843
    5844 SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
    5845 BMSclearMemoryArray(binvals, nbinvars);
    5846 }
    5847 else
    5848 {
    5849 noknapsackconshdlr = FALSE;
    5850 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5851 assert(conshdlrdata != NULL);
    5852 usegubs = conshdlrdata->usegubs;
    5853
    5854 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
    5855
    5856 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
    5857 * change their types to SCIP_VARTYPE_BINARY during presolving
    5858 */
    5859 if( conshdlrdata->reals1size == 0 )
    5860 {
    5861 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
    5862 conshdlrdata->reals1size = 1;
    5863 conshdlrdata->reals1[0] = 0.0;
    5864 }
    5865
    5866 assert(conshdlrdata->reals1size > 0);
    5867
    5868 /* next if condition should normally not be true, because it means that presolving has created more binary
    5869 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
    5870 * transform all integers into their binary representation then it maybe happens
    5871 */
    5872 if( conshdlrdata->reals1size < nbinvars )
    5873 {
    5874 int oldsize = conshdlrdata->reals1size;
    5875
    5876 conshdlrdata->reals1size = nbinvars;
    5877 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
    5878 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
    5879 }
    5880 binvals = conshdlrdata->reals1;
    5881
    5882 /* check for cleared array, all entries have to be zero */
    5883#ifndef NDEBUG
    5884 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
    5885 {
    5886 assert(binvals[tmp] == 0);
    5887 }
    5888#endif
    5889 }
    5890
    5891 tmp = 0;
    5892
    5893 /* relax continuous knapsack constraint:
    5894 * 1. make all variables binary:
    5895 * if x_j is continuous or integer variable substitute:
    5896 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
    5897 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
    5898 * 2. convert coefficients of all variables to positive integers:
    5899 * - scale all coefficients a_j to a~_j integral
    5900 * - substitute x~_j = 1 - x_j if a~_j < 0
    5901 */
    5902
    5903 /* replace integer and continuous variables with binary variables */
    5904 for( i = 0; i < nknapvars; i++ )
    5905 {
    5906 SCIP_VAR* var;
    5907
    5908 var = knapvars[i];
    5909
    5910 if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
    5911 {
    5912 SCIP_Real solval;
    5913 assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
    5914
    5915 solval = SCIPgetSolVal(scip, sol, var);
    5916
    5917 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
    5918 if( SCIPisFeasLT(scip, solval, 0.0 )
    5919 || SCIPisFeasGT(scip, solval, 1.0) )
    5920 {
    5921 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
    5922 solval, SCIPvarGetName(var));
    5923 goto TERMINATE;
    5924 }
    5925
    5926 binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
    5927 if( !noknapsackconshdlr )
    5928 {
    5929 assert(tmpindices != NULL);
    5930
    5931 tmpindices[tmp] = SCIPvarGetProbindex(var);
    5932 ++tmp;
    5933 }
    5934 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
    5935 }
    5936 else if( valscale * knapvals[i] > 0.0 )
    5937 {
    5938 SCIP_VAR** zvlb;
    5939 SCIP_Real* bvlb;
    5940 SCIP_Real* dvlb;
    5941 SCIP_Real bestlbsol;
    5942 int bestlbtype;
    5943 int nvlb;
    5944 int j;
    5945
    5946 /* a_j > 0: substitution with lb or vlb */
    5947 nvlb = SCIPvarGetNVlbs(var);
    5948 zvlb = SCIPvarGetVlbVars(var);
    5949 bvlb = SCIPvarGetVlbCoefs(var);
    5950 dvlb = SCIPvarGetVlbConstants(var);
    5951
    5952 /* search for lb or vlb with maximal bound value */
    5953 bestlbsol = SCIPvarGetLbGlobal(var);
    5954 bestlbtype = -1;
    5955 for( j = 0; j < nvlb; j++ )
    5956 {
    5957 /* use only numerical stable vlb with binary variable z */
    5958 if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
    5959 {
    5960 SCIP_Real vlbsol;
    5961
    5962 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
    5963 (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
    5964 {
    5965 *cutoff = TRUE;
    5966 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
    5968 bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
    5969 goto TERMINATE;
    5970 }
    5971
    5972 assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
    5973 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
    5974 if( SCIPisGE(scip, vlbsol, bestlbsol) )
    5975 {
    5976 bestlbsol = vlbsol;
    5977 bestlbtype = j;
    5978 }
    5979 }
    5980 }
    5981
    5982 /* if no lb or vlb with binary variable was found, we have to abort */
    5983 if( SCIPisInfinity(scip, -bestlbsol) )
    5984 goto TERMINATE;
    5985
    5986 if( bestlbtype == -1 )
    5987 {
    5988 rhs -= valscale * knapvals[i] * bestlbsol;
    5989 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
    5990 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
    5991 }
    5992 else
    5993 {
    5994 assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
    5995 rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
    5996 binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
    5997
    5998 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
    5999 goto TERMINATE;
    6000
    6001 if( !noknapsackconshdlr )
    6002 {
    6003 assert(tmpindices != NULL);
    6004
    6005 tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
    6006 ++tmp;
    6007 }
    6008 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
    6009 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
    6010 bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
    6011 SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
    6012 }
    6013 }
    6014 else
    6015 {
    6016 SCIP_VAR** zvub;
    6017 SCIP_Real* bvub;
    6018 SCIP_Real* dvub;
    6019 SCIP_Real bestubsol;
    6020 int bestubtype;
    6021 int nvub;
    6022 int j;
    6023
    6024 assert(valscale * knapvals[i] < 0.0);
    6025
    6026 /* a_j < 0: substitution with ub or vub */
    6027 nvub = SCIPvarGetNVubs(var);
    6028 zvub = SCIPvarGetVubVars(var);
    6029 bvub = SCIPvarGetVubCoefs(var);
    6030 dvub = SCIPvarGetVubConstants(var);
    6031
    6032 /* search for ub or vub with minimal bound value */
    6033 bestubsol = SCIPvarGetUbGlobal(var);
    6034 bestubtype = -1;
    6035 for( j = 0; j < nvub; j++ )
    6036 {
    6037 /* use only numerical stable vub with active binary variable z */
    6038 if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
    6039 {
    6040 SCIP_Real vubsol;
    6041
    6042 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
    6043 (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
    6044 {
    6045 *cutoff = TRUE;
    6046 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
    6048 bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
    6049 goto TERMINATE;
    6050 }
    6051
    6052 assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
    6053 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
    6054 if( SCIPisLE(scip, vubsol, bestubsol) )
    6055 {
    6056 bestubsol = vubsol;
    6057 bestubtype = j;
    6058 }
    6059 }
    6060 }
    6061
    6062 /* if no ub or vub with binary variable was found, we have to abort */
    6063 if( SCIPisInfinity(scip, bestubsol) )
    6064 goto TERMINATE;
    6065
    6066 if( bestubtype == -1 )
    6067 {
    6068 rhs -= valscale * knapvals[i] * bestubsol;
    6069 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
    6070 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
    6071 }
    6072 else
    6073 {
    6074 assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
    6075 rhs -= valscale * knapvals[i] * dvub[bestubtype];
    6076 binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
    6077
    6078 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
    6079 goto TERMINATE;
    6080
    6081 if( !noknapsackconshdlr )
    6082 {
    6083 assert(tmpindices != NULL);
    6084
    6085 tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
    6086 ++tmp;
    6087 }
    6088 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
    6089 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
    6090 bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
    6091 SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
    6092 }
    6093 }
    6094 }
    6095
    6096 /* convert coefficients of all (now binary) variables to positive integers:
    6097 * - make all coefficients integral
    6098 * - make all coefficients positive (substitute negated variable)
    6099 */
    6100 nconsvars = 0;
    6101
    6102 /* calculate scalar which makes all coefficients integral in relative allowed difference in between
    6103 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
    6104 */
    6106 KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
    6107 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
    6108
    6109 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
    6110 if( !success )
    6111 intscalar = 1.0;
    6112
    6113 /* make all coefficients integral and positive:
    6114 * - scale a~_j = a_j * intscalar
    6115 * - substitute x~_j = 1 - x_j if a~_j < 0
    6116 */
    6117 rhs = rhs * intscalar;
    6118
    6119 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
    6120 minact = 0;
    6121 maxact = 0;
    6122 for( i = 0; i < nbinvars; i++ )
    6123 {
    6124 SCIP_VAR* var;
    6125 SCIP_Longint val;
    6126
    6127 val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
    6128 if( val == 0 )
    6129 continue;
    6130
    6131 if( val > 0 )
    6132 {
    6133 var = binvars[i];
    6134 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
    6135 val, SCIPvarGetName(var), binvals[i], rhs);
    6136 }
    6137 else
    6138 {
    6139 assert(val < 0);
    6140
    6141 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
    6142 val = -val; /*lint !e2704*/
    6143 rhs += val;
    6144 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
    6145 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
    6146 }
    6147
    6148 if( SCIPvarGetLbLocal(var) > 0.5 )
    6149 minact += val;
    6150 if( SCIPvarGetUbLocal(var) > 0.5 )
    6151 maxact += val;
    6152 consvals[nconsvars] = val;
    6153 consvars[nconsvars] = var;
    6154 nconsvars++;
    6155 }
    6156
    6157 if( nconsvars > 0 )
    6158 {
    6159 SCIP_Longint capacity;
    6160
    6161 assert(consvars != NULL);
    6162 assert(consvals != NULL);
    6163 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
    6164
    6165#ifdef SCIP_DEBUG
    6166 {
    6167 SCIP_Real act;
    6168
    6169 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
    6170 act = 0.0;
    6171 for( i = 0; i < nconsvars; ++i )
    6172 {
    6173 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
    6174 SCIPgetSolVal(scip, sol, consvars[i]));
    6175 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
    6176 }
    6177 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
    6178 capacity, rhs, act, minact, maxact);
    6179 }
    6180#endif
    6181
    6182 if( minact > capacity )
    6183 {
    6184 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
    6185 *cutoff = TRUE;
    6186 goto TERMINATE;
    6187 }
    6188
    6189 if( maxact > capacity )
    6190 {
    6191 /* separate lifted cut from relaxed knapsack constraint */
    6192 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
    6193 }
    6194 }
    6195
    6196 TERMINATE:
    6197 /* free data structures */
    6198 if( noknapsackconshdlr)
    6199 {
    6200 SCIPfreeBufferArray(scip, &binvals);
    6201 }
    6202 else
    6203 {
    6204 /* clear binvals */
    6205 for( --tmp; tmp >= 0; --tmp)
    6206 {
    6207 assert(tmpindices != NULL);
    6208 binvals[tmpindices[tmp]] = 0;
    6209 }
    6210 SCIPfreeBufferArray(scip, &tmpindices);
    6211 }
    6212 SCIPfreeBufferArray(scip, &consvals);
    6213 SCIPfreeBufferArray(scip, &consvars);
    6214
    6215 return SCIP_OKAY;
    6216}
    6217
    6218/** separates given knapsack constraint */
    6219static
    6221 SCIP* scip, /**< SCIP data structure */
    6222 SCIP_CONS* cons, /**< knapsack constraint */
    6223 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
    6224 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
    6225 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
    6226 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    6227 int* ncuts /**< pointer to add up the number of found cuts */
    6228 )
    6229{
    6230 SCIP_CONSDATA* consdata;
    6231 SCIP_Bool violated;
    6232
    6233 assert(ncuts != NULL);
    6234 assert(cutoff != NULL);
    6235 *cutoff = FALSE;
    6236
    6237 consdata = SCIPconsGetData(cons);
    6238 assert(consdata != NULL);
    6239
    6240 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
    6241
    6242 /* check knapsack constraint itself for feasibility */
    6243 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
    6244
    6245 if( violated )
    6246 {
    6247 /* add knapsack constraint as LP row to the LP */
    6248 SCIP_CALL( addRelaxation(scip, cons, cutoff) );
    6249 (*ncuts)++;
    6250 }
    6251 else if( sepacuts )
    6252 {
    6253 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
    6254 consdata->capacity, sol, usegubs, cutoff, ncuts) );
    6255 }
    6256
    6257 return SCIP_OKAY;
    6258}
    6259
    6260/** adds coefficient to constraint data */
    6261static
    6263 SCIP* scip, /**< SCIP data structure */
    6264 SCIP_CONS* cons, /**< knapsack constraint */
    6265 SCIP_VAR* var, /**< variable to add to knapsack */
    6266 SCIP_Longint weight /**< weight of variable in knapsack */
    6267 )
    6268{
    6269 SCIP_CONSDATA* consdata;
    6270
    6271 consdata = SCIPconsGetData(cons);
    6272 assert(consdata != NULL);
    6273 assert(SCIPvarIsBinary(var));
    6274 assert(weight > 0);
    6275
    6276 /* add the new coefficient to the LP row */
    6277 if( consdata->row != NULL )
    6278 {
    6279 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
    6280 }
    6281
    6282 /* check for fixed variable */
    6283 if( SCIPvarGetLbGlobal(var) > 0.5 )
    6284 {
    6285 /* variable is fixed to one: reduce capacity */
    6286 consdata->capacity -= weight;
    6287 }
    6288 else if( SCIPvarGetUbGlobal(var) > 0.5 )
    6289 {
    6290 SCIP_Bool negated;
    6291
    6292 /* get binary representative of variable */
    6293 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
    6294
    6295 /* insert coefficient */
    6296 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
    6297 consdata->vars[consdata->nvars] = var;
    6298 consdata->weights[consdata->nvars] = weight;
    6299 consdata->nvars++;
    6300
    6301 /* capture variable */
    6302 SCIP_CALL( SCIPcaptureVar(scip, var) );
    6303
    6304 /* install the rounding locks of variable */
    6305 SCIP_CALL( lockRounding(scip, cons, var) );
    6306
    6307 /* catch events */
    6308 if( SCIPconsIsTransformed(cons) )
    6309 {
    6310 SCIP_CONSHDLRDATA* conshdlrdata;
    6311
    6312 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    6313 assert(conshdlrdata != NULL);
    6314 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
    6316 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
    6317 &consdata->eventdata[consdata->nvars-1]->filterpos) );
    6318
    6319 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
    6320 consdata->existmultaggr = TRUE;
    6321
    6322 /* mark constraint to be propagated and presolved */
    6324 consdata->presolvedtiming = 0;
    6325 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
    6326 }
    6327
    6328 /* update weight sums */
    6329 updateWeightSums(consdata, var, weight);
    6330
    6331 consdata->sorted = FALSE;
    6332 consdata->cliquepartitioned = FALSE;
    6333 consdata->negcliquepartitioned = FALSE;
    6334 consdata->merged = FALSE;
    6335 }
    6336
    6337 return SCIP_OKAY;
    6338}
    6339
    6340/** deletes coefficient at given position from constraint data */
    6341static
    6343 SCIP* scip, /**< SCIP data structure */
    6344 SCIP_CONS* cons, /**< knapsack constraint */
    6345 int pos /**< position of coefficient to delete */
    6346 )
    6347{
    6348 SCIP_CONSDATA* consdata;
    6349 SCIP_VAR* var;
    6350
    6351 consdata = SCIPconsGetData(cons);
    6352 assert(consdata != NULL);
    6353 assert(0 <= pos && pos < consdata->nvars);
    6354
    6355 var = consdata->vars[pos];
    6356 assert(var != NULL);
    6357 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
    6358
    6359 /* delete the coefficient from the LP row */
    6360 if( consdata->row != NULL )
    6361 {
    6362 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
    6363 }
    6364
    6365 /* remove the rounding locks of variable */
    6366 SCIP_CALL( unlockRounding(scip, cons, var) );
    6367
    6368 /* drop events and mark constraint to be propagated and presolved */
    6369 if( SCIPconsIsTransformed(cons) )
    6370 {
    6371 SCIP_CONSHDLRDATA* conshdlrdata;
    6372
    6373 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    6374 assert(conshdlrdata != NULL);
    6376 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
    6377 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
    6378
    6380 consdata->presolvedtiming = 0;
    6381 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
    6382 }
    6383
    6384 /* decrease weight sums */
    6385 updateWeightSums(consdata, var, -consdata->weights[pos]);
    6386
    6387 /* move the last variable to the free slot */
    6388 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
    6389 consdata->weights[pos] = consdata->weights[consdata->nvars-1];
    6390 if( consdata->eventdata != NULL )
    6391 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
    6392
    6393 /* release variable */
    6394 SCIP_CALL( SCIPreleaseVar(scip, &var) );
    6395
    6396 /* try to use old clique partitions */
    6397 if( consdata->cliquepartitioned )
    6398 {
    6399 assert(consdata->cliquepartition != NULL);
    6400 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
    6401 * change the clique number */
    6402 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
    6403 {
    6404 int oldcliqenum;
    6405
    6406 oldcliqenum = consdata->cliquepartition[pos];
    6407 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
    6408
    6409 /* the following if and else cases assure that we have increasing clique numbers */
    6410 if( consdata->cliquepartition[pos] > pos )
    6411 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
    6412 else
    6413 {
    6414 int i;
    6415 int cliquenumbefore;
    6416
    6417 /* if the old clique number was greater than the new one we have to check that before a bigger clique number
    6418 * occurs the same as the old one is still in the cliquepartition */
    6419 if( oldcliqenum > consdata->cliquepartition[pos] )
    6420 {
    6421 for( i = 0; i < consdata->nvars; ++i )
    6422 if( oldcliqenum == consdata->cliquepartition[i] )
    6423 break;
    6424 else if( oldcliqenum < consdata->cliquepartition[i] )
    6425 {
    6426 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
    6427 break;
    6428 }
    6429 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
    6430 * the biggest index, so decrease the number of cliques
    6431 */
    6432 if( i == consdata->nvars )
    6433 --(consdata->ncliques);
    6434 }
    6435 /* if the old clique number was smaller than the new one we have to check the front for an element with
    6436 * clique number minus 1 */
    6437 else if( oldcliqenum < consdata->cliquepartition[pos] )
    6438 {
    6439 cliquenumbefore = consdata->cliquepartition[pos] - 1;
    6440 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
    6441
    6442 if( i < cliquenumbefore )
    6443 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
    6444 }
    6445 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
    6446 else if( pos == consdata->nvars - 1)
    6447 {
    6448 cliquenumbefore = consdata->cliquepartition[pos];
    6449 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
    6450
    6451 if( i < cliquenumbefore )
    6452 --(consdata->ncliques);
    6453 }
    6454 /* if the old clique number is equal to the new one the cliquepartition should be ok */
    6455 }
    6456 }
    6457 else
    6458 --(consdata->ncliques);
    6459 }
    6460
    6461 if( consdata->negcliquepartitioned )
    6462 {
    6463 assert(consdata->negcliquepartition != NULL);
    6464 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
    6465 * change the clique number */
    6466 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
    6467 {
    6468 int oldcliqenum;
    6469
    6470 oldcliqenum = consdata->negcliquepartition[pos];
    6471 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
    6472
    6473 /* the following if and else cases assure that we have increasing clique numbers */
    6474 if( consdata->negcliquepartition[pos] > pos )
    6475 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
    6476 else
    6477 {
    6478 int i;
    6479 int cliquenumbefore;
    6480
    6481 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
    6482 * occurs, the same as the old one occurs */
    6483 if( oldcliqenum > consdata->negcliquepartition[pos] )
    6484 {
    6485 for( i = 0; i < consdata->nvars; ++i )
    6486 if( oldcliqenum == consdata->negcliquepartition[i] )
    6487 break;
    6488 else if( oldcliqenum < consdata->negcliquepartition[i] )
    6489 {
    6490 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
    6491 break;
    6492 }
    6493 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
    6494 * the biggest index, so decrease the number of negated cliques
    6495 */
    6496 if( i == consdata->nvars )
    6497 --(consdata->nnegcliques);
    6498 }
    6499 /* if the old clique number was smaller than the new one we have to check the front for an element with
    6500 * clique number minus 1 */
    6501 else if( oldcliqenum < consdata->negcliquepartition[pos] )
    6502 {
    6503 cliquenumbefore = consdata->negcliquepartition[pos] - 1;
    6504 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
    6505
    6506 if( i < cliquenumbefore )
    6507 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
    6508 }
    6509 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
    6510 else if( pos == consdata->nvars - 1)
    6511 {
    6512 cliquenumbefore = consdata->negcliquepartition[pos];
    6513 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
    6514
    6515 if( i < cliquenumbefore )
    6516 --(consdata->nnegcliques);
    6517 }
    6518 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
    6519 }
    6520 }
    6521 else
    6522 --(consdata->nnegcliques);
    6523 }
    6524
    6525 --(consdata->nvars);
    6526
    6527 return SCIP_OKAY;
    6528}
    6529
    6530/** removes all items with weight zero from knapsack constraint */
    6531static
    6533 SCIP* scip, /**< SCIP data structure */
    6534 SCIP_CONS* cons /**< knapsack constraint */
    6535 )
    6536{
    6537 SCIP_CONSDATA* consdata;
    6538 int v;
    6539
    6540 consdata = SCIPconsGetData(cons);
    6541 assert(consdata != NULL);
    6542
    6543 for( v = consdata->nvars-1; v >= 0; --v )
    6544 {
    6545 if( consdata->weights[v] == 0 )
    6546 {
    6547 SCIP_CALL( delCoefPos(scip, cons, v) );
    6548 }
    6549 }
    6550
    6551 return SCIP_OKAY;
    6552}
    6553
    6554/* perform deletion of variables in all constraints of the constraint handler */
    6555static
    6557 SCIP* scip, /**< SCIP data structure */
    6558 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6559 SCIP_CONS** conss, /**< array of constraints */
    6560 int nconss /**< number of constraints */
    6561 )
    6562{
    6563 SCIP_CONSDATA* consdata;
    6564 int i;
    6565 int v;
    6566
    6567 assert(scip != NULL);
    6568 assert(conshdlr != NULL);
    6569 assert(conss != NULL);
    6570 assert(nconss >= 0);
    6571 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    6572
    6573 /* iterate over all constraints */
    6574 for( i = 0; i < nconss; i++ )
    6575 {
    6576 consdata = SCIPconsGetData(conss[i]);
    6577
    6578 /* constraint is marked, that some of its variables were deleted */
    6579 if( consdata->varsdeleted )
    6580 {
    6581 /* iterate over all variables of the constraint and delete them from the constraint */
    6582 for( v = consdata->nvars - 1; v >= 0; --v )
    6583 {
    6584 if( SCIPvarIsDeleted(consdata->vars[v]) )
    6585 {
    6586 SCIP_CALL( delCoefPos(scip, conss[i], v) );
    6587 }
    6588 }
    6589 consdata->varsdeleted = FALSE;
    6590 }
    6591 }
    6592
    6593 return SCIP_OKAY;
    6594}
    6595
    6596/** replaces multiple occurrences of a variable or its negation by a single coefficient */
    6597static
    6599 SCIP* scip, /**< SCIP data structure */
    6600 SCIP_CONS* cons, /**< knapsack constraint */
    6601 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
    6602 )
    6603{
    6604 SCIP_CONSDATA* consdata;
    6605 int v;
    6606 int prev;
    6607
    6608 assert(scip != NULL);
    6609 assert(cons != NULL);
    6610 assert(cutoff != NULL);
    6611
    6612 consdata = SCIPconsGetData(cons);
    6613 assert(consdata != NULL);
    6614
    6615 *cutoff = FALSE;
    6616
    6617 if( consdata->merged )
    6618 return SCIP_OKAY;
    6619
    6620 if( consdata->nvars <= 1 )
    6621 {
    6622 consdata->merged = TRUE;
    6623 return SCIP_OKAY;
    6624 }
    6625
    6626 assert(consdata->vars != NULL || consdata->nvars == 0);
    6627
    6628 /* sorting array after indices of variables, that's only for faster merging */
    6629 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
    6630 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
    6631
    6632 /* knapsack-sorting (decreasing weights) now lost */
    6633 consdata->sorted = FALSE;
    6634
    6635 v = consdata->nvars - 1;
    6636 prev = v - 1;
    6637 /* loop backwards through the items: deletion only affects rear items */
    6638 while( prev >= 0 )
    6639 {
    6640 SCIP_VAR* var1;
    6641 SCIP_VAR* var2;
    6642 SCIP_Bool negated1;
    6643 SCIP_Bool negated2;
    6644
    6645 negated1 = FALSE;
    6646 negated2 = FALSE;
    6647
    6648 var1 = consdata->vars[v];
    6649 assert(SCIPvarIsBinary(var1));
    6652 {
    6653 var1 = SCIPvarGetNegatedVar(var1);
    6654 negated1 = TRUE;
    6655 }
    6656 assert(var1 != NULL);
    6657
    6658 var2 = consdata->vars[prev];
    6659 assert(SCIPvarIsBinary(var2));
    6662 {
    6663 var2 = SCIPvarGetNegatedVar(var2);
    6664 negated2 = TRUE;
    6665 }
    6666 assert(var2 != NULL);
    6667
    6668 if( var1 == var2 )
    6669 {
    6670 /* both variables are either active or negated */
    6671 if( negated1 == negated2 )
    6672 {
    6673 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
    6674 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
    6675 SCIP_CALL( delCoefPos(scip, cons, v) );
    6676 }
    6677 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
    6678 * and delete item of smaller weight
    6679 */
    6680 else if( consdata->weights[v] == consdata->weights[prev] )
    6681 {
    6682 /* both variables eliminate themselves: w*x + w*(1-x) == w */
    6683 consdata->capacity -= consdata->weights[v];
    6684 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
    6685 SCIP_CALL( delCoefPos(scip, cons, prev) );
    6686
    6687 --prev;
    6688 }
    6689 else if( consdata->weights[v] < consdata->weights[prev] )
    6690 {
    6691 consdata->capacity -= consdata->weights[v];
    6692 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
    6693 assert(consdata->weights[prev] > 0);
    6694 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
    6695 }
    6696 else
    6697 {
    6698 consdata->capacity -= consdata->weights[prev];
    6699 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
    6700 assert(consdata->weights[v] > 0);
    6701 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
    6702 /* restore order iff necessary */
    6703 if( consdata->nvars != v ) /* otherwise the order still stands */
    6704 {
    6705 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
    6706 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
    6707 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
    6708 --prev;
    6709 else /* we need to let v at the same position*/
    6710 {
    6711 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
    6712 /* don't decrease v, the same variable may exist up front */
    6713 --prev;
    6714 continue;
    6715 }
    6716 }
    6717 }
    6718 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
    6719 }
    6720 v = prev;
    6721 --prev;
    6722 }
    6723
    6724 consdata->merged = TRUE;
    6725
    6726 /* check infeasibility */
    6727 if( consdata->onesweightsum > consdata->capacity )
    6728 {
    6729 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
    6730 *cutoff = TRUE;
    6731 return SCIP_OKAY;
    6732 }
    6733
    6734 return SCIP_OKAY;
    6735}
    6736
    6737/** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
    6738 * fixings (dual reductions)
    6739 */
    6740static
    6742 SCIP* scip, /**< SCIP data structure */
    6743 SCIP_CONS* cons, /**< knapsack constraint */
    6744 int* nfixedvars, /**< pointer to count number of fixings */
    6745 int* ndelconss, /**< pointer to count number of deleted constraints */
    6746 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
    6747 )
    6748{
    6749 SCIP_CONSDATA* consdata;
    6750 SCIP_VAR** vars;
    6751 SCIP_Real* profits;
    6752 int* solitems;
    6753 int* nonsolitems;
    6754 int* items;
    6755 SCIP_Real solval;
    6756 SCIP_Bool infeasible;
    6757 SCIP_Bool tightened;
    6758 SCIP_Bool applicable;
    6759 int nsolitems;
    6760 int nnonsolitems;
    6761 int nvars;
    6762 int v;
    6763
    6764 assert(!SCIPconsIsModifiable(cons));
    6765
    6766 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
    6767 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
    6768 * added to the problems have the check flag set to FALSE
    6769 */
    6770 if( !SCIPconsIsChecked(cons) )
    6771 return SCIP_OKAY;
    6772
    6773 consdata = SCIPconsGetData(cons);
    6774 assert(consdata != NULL);
    6775
    6776 nvars = consdata->nvars;
    6777 vars = consdata->vars;
    6778
    6781 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
    6782 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
    6783
    6784 applicable = TRUE;
    6785
    6786 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
    6787 * collect object values which are the profits of the knapsack problem
    6788 */
    6789 for( v = 0; v < nvars; ++v )
    6790 {
    6791 SCIP_VAR* var;
    6792 SCIP_Bool negated;
    6793
    6794 var = vars[v];
    6795 assert(var != NULL);
    6796
    6797 /* the variable should not be (globally) fixed */
    6798 assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
    6799
    6802 {
    6803 applicable = FALSE;
    6804 break;
    6805 }
    6806
    6807 negated = FALSE;
    6808
    6809 /* get the active variable */
    6810 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
    6811 assert(SCIPvarIsActive(var));
    6812
    6813 if( negated )
    6814 profits[v] = SCIPvarGetObj(var);
    6815 else
    6816 profits[v] = -SCIPvarGetObj(var);
    6817
    6818 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
    6819 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
    6820 items[v] = v;
    6821 }
    6822
    6823 if( applicable )
    6824 {
    6825 SCIP_Bool success;
    6826
    6827 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
    6829
    6830 /* solve knapsack problem exactly */
    6831 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
    6832 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
    6833
    6834 if( success )
    6835 {
    6836 SCIP_VAR* var;
    6837
    6838 /* apply solution of the knapsack as dual reductions */
    6839 for( v = 0; v < nsolitems; ++v )
    6840 {
    6841 var = vars[solitems[v]];
    6842 assert(var != NULL);
    6843
    6844 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
    6846 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
    6847 assert(!infeasible);
    6848 assert(tightened);
    6849 (*nfixedvars)++;
    6850 }
    6851
    6852 for( v = 0; v < nnonsolitems; ++v )
    6853 {
    6854 var = vars[nonsolitems[v]];
    6855 assert(var != NULL);
    6856
    6857 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
    6859 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
    6860 assert(!infeasible);
    6861 assert(tightened);
    6862 (*nfixedvars)++;
    6863 }
    6864
    6865 SCIP_CALL( SCIPdelCons(scip, cons) );
    6866 (*ndelconss)++;
    6867 (*deleted) = TRUE;
    6868 }
    6869 }
    6870
    6871 SCIPfreeBufferArray(scip, &nonsolitems);
    6872 SCIPfreeBufferArray(scip, &solitems);
    6873 SCIPfreeBufferArray(scip, &items);
    6874 SCIPfreeBufferArray(scip, &profits);
    6875
    6876 return SCIP_OKAY;
    6877}
    6878
    6879/** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
    6880 * constraint enters the LP by setting the initial and separated flag to FALSE
    6881 */
    6882static
    6884 SCIP* scip, /**< SCIP data structure */
    6885 SCIP_CONS* cons, /**< knapsack constraint */
    6886 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
    6887 )
    6888{
    6889 SCIP_CONSDATA* consdata;
    6890 SCIP_VAR** vars;
    6891 SCIP_VAR* var;
    6892 SCIP_Real offset;
    6893 SCIP_Real scale;
    6894 SCIP_Real objval;
    6895 SCIP_Bool applicable;
    6896 SCIP_Bool negated;
    6897 int nobjvars;
    6898 int nvars;
    6899 int v;
    6900
    6901 assert(scip != NULL);
    6902 assert(cons != NULL);
    6903 assert(conshdlrdata != NULL);
    6904
    6905 consdata = SCIPconsGetData(cons);
    6906 assert(consdata != NULL);
    6907
    6908 nvars = consdata->nvars;
    6909 nobjvars = SCIPgetNObjVars(scip);
    6910
    6911 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
    6912 * and/or separated flag is set to FALSE
    6913 */
    6914 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
    6915 return SCIP_OKAY;
    6916
    6917 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
    6918 * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
    6919 */
    6920 if( nobjvars == 0 )
    6921 return SCIP_OKAY;
    6922
    6923 vars = consdata->vars;
    6924 assert(vars != NULL);
    6925
    6926 applicable = TRUE;
    6927 offset = 0.0;
    6928 scale = 1.0;
    6929
    6930 for( v = 0; v < nvars && applicable; ++v )
    6931 {
    6932 negated = FALSE;
    6933 var = vars[v];
    6934 assert(var != NULL);
    6935
    6936 if( SCIPvarIsNegated(var) )
    6937 {
    6938 negated = TRUE;
    6939 var = SCIPvarGetNegatedVar(var);
    6940 assert(var != NULL);
    6941 }
    6942
    6943 objval = SCIPvarGetObj(var);
    6944
    6945 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
    6946 if( SCIPisZero(scip, objval) )
    6947 applicable = FALSE;
    6948 else
    6949 {
    6950 SCIP_Real weight;
    6951
    6952 weight = (SCIP_Real)consdata->weights[v];
    6953
    6954 if( negated )
    6955 {
    6956 if( v == 0 )
    6957 {
    6958 /* the first variable defines the scale */
    6959 scale = weight / -objval;
    6960
    6961 offset += weight;
    6962 }
    6963 else if( SCIPisEQ(scip, -objval * scale, weight) )
    6964 offset += weight;
    6965 else
    6966 applicable = FALSE;
    6967 }
    6968 else if( v == 0 )
    6969 {
    6970 /* the first variable define the scale */
    6971 scale = weight / objval;
    6972 }
    6973 else if( !SCIPisEQ(scip, objval * scale, weight) )
    6974 applicable = FALSE;
    6975 }
    6976 }
    6977
    6978 if( applicable )
    6979 {
    6980 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
    6981 {
    6982 SCIP_Real cutoffbound;
    6983
    6984 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
    6987
    6988 cutoffbound = (consdata->capacity - offset) / scale;
    6989
    6990 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
    6991 SCIPconsGetName(cons), cutoffbound);
    6992
    6993 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
    6994 * still excepted
    6995 */
    6996 cutoffbound += SCIPcutoffbounddelta(scip);
    6997
    6998 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
    6999 SCIPconsGetName(cons), cutoffbound);
    7000
    7001 if( cutoffbound < SCIPgetCutoffbound(scip) )
    7002 {
    7003 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
    7004
    7005 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
    7006 }
    7007 else
    7008 {
    7009 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
    7010 * propagation
    7011 */
    7014 }
    7015 }
    7016 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
    7017 {
    7018 SCIP_Real lowerbound;
    7019
    7020 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
    7023
    7024 lowerbound = (consdata->capacity - offset) / scale;
    7025
    7026 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
    7027 SCIPconsGetName(cons), lowerbound);
    7028
    7030 }
    7031 }
    7032
    7033 return SCIP_OKAY;
    7034}
    7035
    7036/** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
    7037 * weight of one variable is greater or equal another weight and both variables are in the same cliques */
    7038static
    7040 SCIP* scip, /**< SCIP data structure */
    7041 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
    7042 SCIP_VAR** vars, /**< array for sorted variables */
    7043 SCIP_Longint* weights, /**< array for sorted weights */
    7044 int* cliquestartposs, /**< starting position array for each clique */
    7045 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
    7046 )
    7047{
    7048 SCIP_VAR** origvars;
    7049 int norigvars;
    7050 SCIP_Longint* origweights;
    7051 int* cliquepartition;
    7052 int ncliques;
    7053
    7054 SCIP_VAR*** varpointers;
    7055 SCIP_Longint** weightpointers;
    7056 int* cliquecount;
    7057
    7058 int nextpos;
    7059 int c;
    7060 int v;
    7061
    7062 assert(scip != NULL);
    7063 assert(consdata != NULL);
    7064 assert(vars != NULL);
    7065 assert(weights != NULL);
    7066 assert(cliquestartposs != NULL);
    7067
    7068 origweights = consdata->weights;
    7069 origvars = consdata->vars;
    7070 norigvars = consdata->nvars;
    7071
    7072 assert(origvars != NULL || norigvars == 0);
    7073 assert(origweights != NULL || norigvars == 0);
    7074
    7075 if( norigvars == 0 )
    7076 return SCIP_OKAY;
    7077
    7078 if( usenegatedclique )
    7079 {
    7080 assert(consdata->negcliquepartitioned);
    7081
    7082 cliquepartition = consdata->negcliquepartition;
    7083 ncliques = consdata->nnegcliques;
    7084 }
    7085 else
    7086 {
    7087 assert(consdata->cliquepartitioned);
    7088
    7089 cliquepartition = consdata->cliquepartition;
    7090 ncliques = consdata->ncliques;
    7091 }
    7092
    7093 assert(cliquepartition != NULL);
    7094 assert(ncliques > 0);
    7095
    7096 /* we first count all clique items and alloc temporary memory for a bucket sort */
    7097 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
    7098 BMSclearMemoryArray(cliquecount, ncliques);
    7099
    7100 /* first we count for each clique the number of elements */
    7101 for( v = norigvars - 1; v >= 0; --v )
    7102 {
    7103 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
    7104 ++(cliquecount[cliquepartition[v]]);
    7105 }
    7106
    7107 /*@todo: maybe it is better to put largest cliques up front */
    7108
    7109#ifndef NDEBUG
    7110 BMSclearMemoryArray(vars, norigvars);
    7111 BMSclearMemoryArray(weights, norigvars);
    7112#endif
    7113 SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
    7114 SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
    7115
    7116 nextpos = 0;
    7117 /* now we initialize all start pointers for each clique, so they will be ordered */
    7118 for( c = 0; c < ncliques; ++c )
    7119 {
    7120 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
    7121 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
    7122 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
    7123 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
    7124 * vars[7]
    7125 *
    7126 */
    7127 varpointers[c] = (SCIP_VAR**) (vars + nextpos);
    7128 cliquestartposs[c] = nextpos;
    7129 weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
    7130 assert(cliquecount[c] > 0);
    7131 nextpos += cliquecount[c];
    7132 assert(nextpos > 0);
    7133 }
    7134 assert(nextpos == norigvars);
    7135 cliquestartposs[c] = nextpos;
    7136
    7137 /* now we copy all variable and weights to the right order */
    7138 for( v = 0; v < norigvars; ++v )
    7139 {
    7140 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
    7141 ++(varpointers[cliquepartition[v]]);
    7142 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
    7143 ++(weightpointers[cliquepartition[v]]);
    7144 }
    7145#ifndef NDEBUG
    7146 for( v = 0; v < norigvars; ++v )
    7147 {
    7148 assert(vars[v] != NULL);
    7149 assert(weights[v] > 0);
    7150 }
    7151#endif
    7152
    7153 /* free temporary memory */
    7154 SCIPfreeBufferArray(scip, &weightpointers);
    7155 SCIPfreeBufferArray(scip, &varpointers);
    7156 SCIPfreeBufferArray(scip, &cliquecount);
    7157
    7158 return SCIP_OKAY;
    7159}
    7160
    7161/** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
    7162static
    7164 SCIP* scip, /**< SCIP data structure */
    7165 SCIP_CONS* cons, /**< knapsack constraint */
    7166 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
    7167 * information is not needed; in this case, we apply all fixings
    7168 * instead of stopping after the first infeasible one */
    7169 )
    7170{
    7171 SCIP_CONSDATA* consdata;
    7172 int v;
    7173
    7174 assert(scip != NULL);
    7175 assert(cons != NULL);
    7176
    7177 consdata = SCIPconsGetData(cons);
    7178 assert(consdata != NULL);
    7179 assert(consdata->nvars == 0 || consdata->vars != NULL);
    7180
    7181 if( cutoff != NULL )
    7182 *cutoff = FALSE;
    7183
    7184 SCIPdebugMsg(scip, "apply fixings:\n");
    7186
    7187 /* check infeasibility */
    7188 if ( consdata->onesweightsum > consdata->capacity )
    7189 {
    7190 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
    7191
    7192 if( cutoff != NULL )
    7193 *cutoff = TRUE;
    7194
    7195 return SCIP_OKAY;
    7196 }
    7197
    7198 /* all multi-aggregations should be resolved */
    7199 consdata->existmultaggr = FALSE;
    7200
    7201 v = 0;
    7202 while( v < consdata->nvars )
    7203 {
    7204 SCIP_VAR* var;
    7205
    7206 var = consdata->vars[v];
    7207 assert(SCIPvarIsBinary(var));
    7208
    7209 if( SCIPvarGetLbGlobal(var) > 0.5 )
    7210 {
    7211 assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
    7212 consdata->capacity -= consdata->weights[v];
    7213 SCIP_CALL( delCoefPos(scip, cons, v) );
    7214 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
    7215 }
    7216 else if( SCIPvarGetUbGlobal(var) < 0.5 )
    7217 {
    7218 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
    7219 SCIP_CALL( delCoefPos(scip, cons, v) );
    7220 }
    7221 else
    7222 {
    7223 SCIP_VAR* repvar;
    7224 SCIP_VAR* negvar;
    7225 SCIP_VAR* workvar;
    7226 SCIP_Longint weight;
    7227 SCIP_Bool negated;
    7228
    7229 weight = consdata->weights[v];
    7230
    7231 /* get binary representative of variable */
    7232 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
    7233 assert(repvar != NULL);
    7234
    7235 /* check for multi-aggregation */
    7236 if( SCIPvarIsNegated(repvar) )
    7237 {
    7238 workvar = SCIPvarGetNegatedVar(repvar);
    7239 assert(workvar != NULL);
    7240 negated = TRUE;
    7241 }
    7242 else
    7243 {
    7244 workvar = repvar;
    7245 negated = FALSE;
    7246 }
    7247
    7248 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
    7249 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
    7250 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
    7251 *
    7252 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
    7253 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
    7254 *
    7255 * The explanation for the following block:
    7256 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
    7257 * weight * (a_1*y_1 + ... + a_n*y_n + c).
    7258 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
    7259 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
    7260 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
    7261 * 2) For all replacement variable we check:
    7262 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
    7263 * capacity -= weight * a_i caused by the negation of y_i.
    7264 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
    7265 * 3a) If repvar was not negated we need to subtract weight * c from capacity.
    7266 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
    7267 * weight in this case.
    7268 */
    7270 {
    7271 SCIP_VAR** aggrvars;
    7272 SCIP_Real* aggrscalars;
    7273 SCIP_Real aggrconst;
    7274 int naggrvars;
    7275 int i;
    7276
    7278 naggrvars = SCIPvarGetMultaggrNVars(workvar);
    7279 aggrvars = SCIPvarGetMultaggrVars(workvar);
    7280 aggrscalars = SCIPvarGetMultaggrScalars(workvar);
    7281 aggrconst = SCIPvarGetMultaggrConstant(workvar);
    7282 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
    7283
    7284 if( !SCIPisIntegral(scip, weight * aggrconst) )
    7285 {
    7286 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
    7287 return SCIP_ERROR;
    7288 }
    7289
    7290 /* if workvar was negated, we have to flip the weight */
    7291 if( negated )
    7292 weight *= -1;
    7293
    7294 for( i = naggrvars - 1; i >= 0; --i )
    7295 {
    7296 assert(aggrvars != NULL);
    7297 assert(aggrscalars != NULL);
    7298
    7299 if( !SCIPvarIsBinary(aggrvars[i]) )
    7300 {
    7301 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
    7302 SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
    7303 return SCIP_ERROR;
    7304 }
    7305 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
    7306 {
    7307 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
    7308 return SCIP_ERROR;
    7309 }
    7310 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
    7311 if( SCIPisNegative(scip, weight * aggrscalars[i]) )
    7312 {
    7313 SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar) );
    7314 assert(negvar != NULL);
    7315 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
    7316 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
    7317 }
    7318 else
    7319 {
    7320 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
    7321 }
    7322 }
    7323 /* delete old coefficient */
    7324 SCIP_CALL( delCoefPos(scip, cons, v) );
    7325
    7326 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
    7327 if( negated )
    7328 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
    7329 else
    7330 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
    7331
    7332 if( consdata->capacity < 0 )
    7333 {
    7334 if( cutoff != NULL )
    7335 {
    7336 *cutoff = TRUE;
    7337 break;
    7338 }
    7339 }
    7340 }
    7341 /* check, if the variable should be replaced with the representative */
    7342 else if( repvar != var )
    7343 {
    7344 /* delete old (aggregated) variable */
    7345 SCIP_CALL( delCoefPos(scip, cons, v) );
    7346
    7347 /* add representative instead */
    7348 SCIP_CALL( addCoef(scip, cons, repvar, weight) );
    7349 }
    7350 else
    7351 ++v;
    7352 }
    7353 }
    7354 assert(consdata->onesweightsum == 0);
    7355
    7356 SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
    7358
    7359 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
    7360 * clean up the constraint
    7361 */
    7362 if( cutoff != NULL && !(*cutoff) )
    7363 {
    7364 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    7365 SCIPdebugMsg(scip, "after applyFixings and merging:\n");
    7367 }
    7368
    7369 return SCIP_OKAY;
    7370}
    7371
    7372
    7373/** propagation method for knapsack constraints */
    7374static
    7376 SCIP* scip, /**< SCIP data structure */
    7377 SCIP_CONS* cons, /**< knapsack constraint */
    7378 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
    7379 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
    7380 int* nfixedvars, /**< pointer to count number of fixings */
    7381 SCIP_Bool usenegatedclique /**< should negated clique information be used */
    7382 )
    7383{
    7384 SCIP_CONSDATA* consdata;
    7385 SCIP_Bool infeasible;
    7386 SCIP_Bool tightened;
    7387 SCIP_Longint* secondmaxweights;
    7388 SCIP_Longint minweightsum;
    7389 SCIP_Longint residualcapacity;
    7390
    7391 int nvars;
    7392 int i;
    7393 int nnegcliques;
    7394
    7395 SCIP_VAR** myvars;
    7396 SCIP_Longint* myweights;
    7397 int* cliquestartposs;
    7398 int* cliqueendposs;
    7399 SCIP_Longint localminweightsum;
    7400 SCIP_Bool foundmax;
    7401 int c;
    7402
    7403 assert(scip != NULL);
    7404 assert(cons != NULL);
    7405 assert(cutoff != NULL);
    7406 assert(redundant != NULL);
    7407 assert(nfixedvars != NULL);
    7408
    7409 consdata = SCIPconsGetData(cons);
    7410 assert(consdata != NULL);
    7411
    7412 *cutoff = FALSE;
    7413 *redundant = FALSE;
    7414
    7415 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
    7416
    7417 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
    7419 {
    7420 SCIP_CALL( SCIPincConsAge(scip, cons) );
    7421 }
    7422
    7423#ifndef NDEBUG
    7424 /* assert that only active or negated variables are present */
    7425 for( i = 0; i < consdata->nvars && consdata->merged; ++i )
    7426 {
    7427 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
    7428 }
    7429#endif
    7430
    7431 usenegatedclique = usenegatedclique && consdata->merged;
    7432
    7433 /* init for debugging */
    7434 myvars = NULL;
    7435 myweights = NULL;
    7436 cliquestartposs = NULL;
    7437 secondmaxweights = NULL;
    7438 minweightsum = 0;
    7439 nvars = consdata->nvars;
    7440 /* make sure, the items are sorted by non-increasing weight */
    7441 sortItems(consdata);
    7442
    7443 do
    7444 {
    7445 localminweightsum = 0;
    7446
    7447 /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
    7448 * a negated clique means, that at most one of the clique variables can be zero
    7449 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
    7450 *
    7451 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
    7452 * since replacing i with the element of maximal weight leads to infeasibility
    7453 */
    7454 if( usenegatedclique && nvars > 0 )
    7455 {
    7456 SCIP_CONSHDLRDATA* conshdlrdata;
    7457 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    7458 assert(conshdlrdata != NULL);
    7459
    7460 /* compute clique partitions */
    7461 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
    7462 nnegcliques = consdata->nnegcliques;
    7463
    7464 /* if we have no real negated cliques we can stop here */
    7465 if( nnegcliques == nvars )
    7466 {
    7467 /* run the standard algorithm that does not involve cliques */
    7468 usenegatedclique = FALSE;
    7469 break;
    7470 }
    7471
    7472 /* allocate temporary memory and initialize it */
    7473 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
    7474 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
    7475 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
    7476 SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
    7477 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
    7478 BMSclearMemoryArray(secondmaxweights, nnegcliques);
    7479
    7480 /* resort variables to avoid quadratic algorithm later on */
    7481 SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
    7482
    7483 /* save the end positions of the cliques because start positions are moved in the following loop */
    7484 for( c = 0; c < nnegcliques; ++c )
    7485 {
    7486 cliqueendposs[c] = cliquestartposs[c+1] - 1;
    7487 assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
    7488 }
    7489
    7490 c = 0;
    7491 foundmax = FALSE;
    7492 i = 0;
    7493
    7494 while( i < nvars )
    7495 {
    7496 /* ignore variables of the negated clique which are fixed to one since these are counted in
    7497 * consdata->onesweightsum
    7498 */
    7499
    7500 /* if there are only one variable negated cliques left we can stop */
    7501 if( nnegcliques - c == nvars - i )
    7502 {
    7503 minweightsum += localminweightsum;
    7504 localminweightsum = 0;
    7505 break;
    7506 }
    7507
    7508 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
    7509 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
    7510 * other clique variables to one
    7511 */
    7512 if( cliquestartposs[c] == i )
    7513 {
    7514 assert(myweights[i] > 0);
    7515 ++c;
    7516 minweightsum += localminweightsum;
    7517 localminweightsum = 0;
    7518 foundmax = TRUE;
    7519
    7520 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
    7521 foundmax = FALSE;
    7522
    7523 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
    7524 {
    7525 ++i;
    7526 continue;
    7527 }
    7528 }
    7529
    7530 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
    7531 {
    7532 assert(myweights[i] > 0);
    7533
    7534 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
    7535 {
    7536 assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
    7537
    7538 if( !foundmax )
    7539 {
    7540 foundmax = TRUE;
    7541
    7542 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
    7543 cliquestartposs[c - 1] = i;
    7544 ++i;
    7545
    7546 continue;
    7547 }
    7548 /* memorize second max weight for each clique */
    7549 if( secondmaxweights[c - 1] == 0 )
    7550 secondmaxweights[c - 1] = myweights[i];
    7551
    7552 localminweightsum += myweights[i];
    7553 }
    7554 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
    7555 else
    7556 {
    7557 int v;
    7558 /* fix all other variables of the negated clique to 1 */
    7559 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
    7560 {
    7561 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
    7562 {
    7563 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
    7564 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
    7565
    7566 if( infeasible )
    7567 {
    7568 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
    7569
    7570 /* analyze the infeasibility if conflict analysis is applicable */
    7572 {
    7573 /* conflict analysis can only be applied in solving stage */
    7575
    7576 /* initialize the conflict analysis */
    7578
    7579 /* add the two variables which are fixed to zero within a negated clique */
    7580 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
    7581 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
    7582
    7583 /* start the conflict analysis */
    7585 }
    7586 *cutoff = TRUE;
    7587 break;
    7588 }
    7589 assert(tightened);
    7590 ++(*nfixedvars);
    7592 }
    7593 }
    7594
    7595 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
    7596 localminweightsum = 0;
    7597 /* we can jump to the end of this clique */
    7598 i = cliqueendposs[c - 1];
    7599
    7600 if( *cutoff )
    7601 break;
    7602 }
    7603 }
    7604 ++i;
    7605 }
    7606 /* add last clique minweightsum */
    7607 minweightsum += localminweightsum;
    7608
    7609 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
    7610 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
    7611
    7612 /* check, if weights of fixed variables don't exceeds knapsack capacity */
    7613 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
    7614 {
    7615 SCIP_Longint maxcliqueweight = -1LL;
    7616
    7617 /* loop over cliques */
    7618 for( c = 0; c < nnegcliques; ++c )
    7619 {
    7620 SCIP_VAR* maxvar;
    7621 SCIP_Bool maxvarfixed;
    7622 int endvarposclique;
    7623 int startvarposclique;
    7624
    7625 assert(myvars != NULL);
    7626 assert(nnegcliques == consdata->nnegcliques);
    7627 assert(myweights != NULL);
    7628 assert(secondmaxweights != NULL);
    7629 assert(cliquestartposs != NULL);
    7630
    7631 endvarposclique = cliqueendposs[c];
    7632 startvarposclique = cliquestartposs[c];
    7633
    7634 maxvar = myvars[startvarposclique];
    7635
    7636 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
    7637 if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
    7638 continue;
    7639
    7640 maxcliqueweight = myweights[startvarposclique];
    7641 maxvarfixed = FALSE;
    7642 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
    7643 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
    7644 * exceeds the capacity the maximum weight variable can be fixed to zero.
    7645 */
    7646 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
    7647 {
    7648#ifndef NDEBUG
    7649 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
    7650#endif
    7651 assert(maxcliqueweight >= secondmaxweights[c]);
    7652 assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
    7653
    7654 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
    7656 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
    7657 assert(consdata->onesweightsum == oldonesweightsum);
    7658 assert(!infeasible);
    7659 assert(tightened);
    7660 (*nfixedvars)++;
    7661 maxvarfixed = TRUE;
    7662 }
    7663 /* the remaining cliques are singletons such that all subsequent variables have a weight that
    7664 * fits into the knapsack
    7665 */
    7666 else if( nnegcliques - c == nvars - startvarposclique )
    7667 break;
    7668 /* early termination of the remaining loop because no further variable fixings are possible:
    7669 *
    7670 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
    7671 * largest was set to 0) does not suffice to infer additional variable fixings because
    7672 *
    7673 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
    7674 * - their second largest elements are at least as large as the smallest weight of the knapsack
    7675 */
    7676 else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
    7677 break;
    7678
    7679 /* loop over items with non-maximal weight (omitting the first position) */
    7680 for( i = endvarposclique; i > startvarposclique; --i )
    7681 {
    7682 /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
    7683 * messed up the clique preprocessing in the previous loop to filter those variables out */
    7684 assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
    7685
    7686 /* only check variables of negated cliques for which no variable is locally fixed */
    7687 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
    7688 {
    7689 assert(maxcliqueweight >= myweights[i]);
    7690 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
    7691
    7692 /* we fix the members of this clique with non-maximal weight in two cases to 1:
    7693 *
    7694 * the maxvar was already fixed to 0 because it has a huge gain.
    7695 *
    7696 * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
    7697 * since replacing i with the element of maximal weight leads to infeasibility */
    7698 if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
    7699 {
    7700#ifndef NDEBUG
    7701 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
    7702#endif
    7703 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
    7704 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
    7705 assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
    7706 assert(!infeasible);
    7707 assert(tightened);
    7708 ++(*nfixedvars);
    7710
    7711 /* update minweightsum because now the variable is fixed to one and its weight is counted by
    7712 * consdata->onesweightsum
    7713 */
    7714 minweightsum -= myweights[i];
    7715 assert(minweightsum >= 0);
    7716 }
    7717 else
    7718 break;
    7719 }
    7720 }
    7721#ifndef NDEBUG
    7722 /* in debug mode, we assert that we did not miss possible fixings by the break above */
    7723 for( ; i > startvarposclique; --i )
    7724 {
    7725 SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
    7726 SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
    7727
    7728 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
    7729 assert(varisfixed || !exceedscapacity);
    7730 }
    7731#endif
    7732 }
    7733 }
    7734 SCIPfreeBufferArray(scip, &secondmaxweights);
    7735 SCIPfreeBufferArray(scip, &cliqueendposs);
    7736 SCIPfreeBufferArray(scip, &cliquestartposs);
    7737 SCIPfreeBufferArray(scip, &myweights);
    7738 SCIPfreeBufferArray(scip, &myvars);
    7739 }
    7740
    7741 assert(consdata->negcliquepartitioned || minweightsum == 0);
    7742 }
    7743 while( FALSE );
    7744
    7745 assert(usenegatedclique || minweightsum == 0);
    7746 /* check, if weights of fixed variables already exceed knapsack capacity */
    7747 if( consdata->capacity < minweightsum + consdata->onesweightsum )
    7748 {
    7749 SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
    7750 consdata->onesweightsum, consdata->capacity);
    7751
    7753 *cutoff = TRUE;
    7754
    7755 /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
    7757 {
    7758 /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
    7759 SCIP_Longint weight;
    7760
    7761 weight = 0;
    7762
    7764
    7765 for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
    7766 {
    7767 if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
    7768 {
    7769 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
    7770 weight += consdata->weights[i];
    7771 }
    7772 }
    7773
    7775 }
    7776
    7777 return SCIP_OKAY;
    7778 }
    7779
    7780 /* the algorithm below is a special case of propagation involving negated cliques */
    7781 if( !usenegatedclique )
    7782 {
    7783 assert(consdata->sorted);
    7784 residualcapacity = consdata->capacity - consdata->onesweightsum;
    7785
    7786 /* fix all variables to zero, that don't fit into the knapsack anymore */
    7787 for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
    7788 {
    7789 /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
    7790 * to zero
    7791 */
    7792 if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
    7793 {
    7794 if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
    7795 {
    7796 assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
    7797 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
    7799 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
    7800 assert(!infeasible);
    7801 assert(tightened);
    7802 (*nfixedvars)++;
    7803 }
    7804 }
    7805 }
    7806 }
    7807
    7808 /* check if the knapsack is now redundant */
    7809 if( !SCIPconsIsModifiable(cons) )
    7810 {
    7811 SCIP_Longint unfixedweightsum = consdata->onesweightsum;
    7812
    7813 /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
    7814 for( i = 0; i < nvars; ++i )
    7815 {
    7816 if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
    7817 {
    7818 unfixedweightsum += consdata->weights[i];
    7819
    7820 /* the weight sum is larger than the capacity, so the constraint is not redundant */
    7821 if( unfixedweightsum > consdata->capacity )
    7822 return SCIP_OKAY;
    7823 }
    7824 }
    7825 /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
    7826 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
    7827 SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
    7829 *redundant = TRUE;
    7830 }
    7831
    7832 return SCIP_OKAY;
    7833}
    7834
    7835/** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
    7836 * containing all negated variables of this knapsack constraint
    7837 */
    7838static
    7840 SCIP* scip, /**< SCIP data structure */
    7841 SCIP_CONS* cons, /**< knapsack constraint */
    7842 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    7843 int* naddconss /**< pointer to count number of added constraints */
    7844 )
    7845{
    7846 SCIP_CONS* newcons;
    7847 SCIP_CONSDATA* consdata;
    7848
    7849 assert(scip != NULL);
    7850 assert(cons != NULL);
    7851 assert(ndelconss != NULL);
    7852 assert(naddconss != NULL);
    7853
    7854 consdata = SCIPconsGetData(cons);
    7855 assert(consdata != NULL);
    7856 assert(consdata->nvars > 1);
    7857
    7858 /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
    7859 if( consdata->nvars == 2 )
    7860 {
    7861 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
    7862
    7863 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
    7867 SCIPconsIsStickingAtNode(cons)) );
    7868 }
    7869 /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
    7870 * containing all negated variables of the knapsack
    7871 */
    7872 else
    7873 {
    7874 SCIP_VAR** consvars;
    7875
    7876 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
    7877
    7878 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
    7879 SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
    7880
    7881 SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
    7885 SCIPconsIsStickingAtNode(cons)) );
    7886
    7887 SCIPfreeBufferArray(scip, &consvars);
    7888 }
    7889
    7890 /* add the upgraded constraint to the problem */
    7891 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
    7892 ++(*naddconss);
    7893
    7894 /* remove the underlying constraint from the problem */
    7895 SCIP_CALL( SCIPdelCons(scip, cons) );
    7896 ++(*ndelconss);
    7897
    7898 return SCIP_OKAY;
    7899}
    7900
    7901/** delete redundant variables
    7902 *
    7903 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
    7904 *
    7905 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
    7906 * => x4, x5 always fits into the knapsack, so we can delete them
    7907 *
    7908 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
    7909 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
    7910 */
    7911static
    7913 SCIP* scip, /**< SCIP data structure */
    7914 SCIP_CONS* cons, /**< knapsack constraint */
    7915 SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
    7916 int splitpos, /**< split position till when all front items are fitting, splitpos is the
    7917 * first which did not fit */
    7918 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
    7919 int* nchgsides, /**< pointer to store the amount of changed sides */
    7920 int* naddconss /**< pointer to count number of added constraints */
    7921 )
    7922{
    7923 SCIP_CONSHDLRDATA* conshdlrdata;
    7924 SCIP_CONSDATA* consdata;
    7925 SCIP_VAR** vars;
    7926 SCIP_Longint* weights;
    7927 SCIP_Longint capacity;
    7928 SCIP_Longint gcd;
    7929 int nvars;
    7930 int w;
    7931
    7932 assert(scip != NULL);
    7933 assert(cons != NULL);
    7934 assert(nchgcoefs != NULL);
    7935 assert(nchgsides != NULL);
    7936 assert(naddconss != NULL);
    7937
    7938 consdata = SCIPconsGetData(cons);
    7939 assert(consdata != NULL);
    7940 assert(0 < frontsum && frontsum < consdata->weightsum);
    7941 assert(0 < splitpos && splitpos < consdata->nvars);
    7942
    7943 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    7944 assert(conshdlrdata != NULL);
    7945
    7946 vars = consdata->vars;
    7947 weights = consdata->weights;
    7948 nvars = consdata->nvars;
    7949 capacity = consdata->capacity;
    7950
    7951 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    7952 * weight must not be sorted by their index
    7953 */
    7954#ifndef NDEBUG
    7955 for( w = nvars - 1; w > 0; --w )
    7956 assert(weights[w] <= weights[w-1]);
    7957#endif
    7958
    7959 /* if there are no variables rear to splitpos, the constraint has no redundant variables */
    7960 if( consdata->nvars - 1 == splitpos )
    7961 return SCIP_OKAY;
    7962
    7963 assert(frontsum + weights[splitpos] > capacity);
    7964
    7965 /* detect redundant variables */
    7966 if( consdata->weightsum - weights[splitpos] <= capacity )
    7967 {
    7968 /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
    7969 * fit
    7970 */
    7971 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
    7972
    7973 /* delete items and update capacity */
    7974 for( w = nvars - 1; w > splitpos; --w )
    7975 {
    7976 consdata->capacity -= weights[w];
    7977 SCIP_CALL( delCoefPos(scip, cons, w) );
    7978 }
    7979 assert(w == splitpos);
    7980
    7981 ++(*nchgsides);
    7982 *nchgcoefs += (nvars - splitpos);
    7983
    7984 /* division by greatest common divisor */
    7985 gcd = weights[w];
    7986 for( ; w >= 0 && gcd > 1; --w )
    7987 {
    7988 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
    7989 }
    7990
    7991 /* normalize if possible */
    7992 if( gcd > 1 )
    7993 {
    7994 for( w = splitpos; w >= 0; --w )
    7995 {
    7996 consdataChgWeight(consdata, w, weights[w]/gcd);
    7997 }
    7998 (*nchgcoefs) += nvars;
    7999
    8000 consdata->capacity /= gcd;
    8001 ++(*nchgsides);
    8002 }
    8003
    8004 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8005 * weight must not be sorted by their index
    8006 */
    8007#ifndef NDEBUG
    8008 for( w = consdata->nvars - 1; w > 0; --w )
    8009 assert(weights[w] <= weights[w - 1]);
    8010#endif
    8011 }
    8012 /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
    8013 * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
    8014 * splitpos and needs to fit into the knapsack
    8015 */
    8016 else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
    8017 {
    8018 int* clqpart;
    8019 int nclq;
    8020 int len;
    8021
    8022 len = nvars - (splitpos + 1);
    8023 /* allocate temporary memory */
    8024 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
    8025
    8026 /* calculate clique partition */
    8027 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
    8028
    8029 /* check if we found at least one clique */
    8030 if( nclq < len )
    8031 {
    8032 SCIP_Longint maxactduetoclq;
    8033 int cliquenum;
    8034
    8035 maxactduetoclq = 0;
    8036 cliquenum = 0;
    8037
    8038 /* calculate maximum activity due to cliques */
    8039 for( w = 0; w < len; ++w )
    8040 {
    8041 assert(clqpart[w] >= 0 && clqpart[w] <= w);
    8042 if( clqpart[w] == cliquenum )
    8043 {
    8044 maxactduetoclq += weights[w + splitpos + 1];
    8045 ++cliquenum;
    8046 }
    8047 }
    8048
    8049 /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
    8050 * so delete them and create for all clique the corresponding clique constraints and update the capacity
    8051 */
    8052 if( frontsum + maxactduetoclq <= capacity )
    8053 {
    8054 SCIP_VAR** clqvars;
    8055 int nclqvars;
    8056 int c;
    8057
    8058 assert(maxactduetoclq < weights[splitpos]);
    8059
    8060 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
    8061
    8062 /* allocate temporary memory */
    8063 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
    8064
    8065 for( c = 0; c < nclq; ++c )
    8066 {
    8067 nclqvars = 0;
    8068 for( w = 0; w < len; ++w )
    8069 {
    8070 if( clqpart[w] == c )
    8071 {
    8072 clqvars[nclqvars] = vars[w + splitpos + 1];
    8073 ++nclqvars;
    8074 }
    8075 }
    8076
    8077 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
    8078 if( nclqvars > 1 )
    8079 {
    8080 SCIP_CONS* cliquecons;
    8081 char name[SCIP_MAXSTRLEN];
    8082
    8083 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
    8084 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
    8088 SCIPconsIsStickingAtNode(cons)) );
    8089
    8090 /* add the special constraint to the problem */
    8091 SCIPdebugMsg(scip, " -> adding clique constraint: ");
    8092 SCIPdebugPrintCons(scip, cliquecons, NULL);
    8093 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    8094 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    8095 ++(*naddconss);
    8096 }
    8097 }
    8098
    8099 /* delete items and update capacity */
    8100 for( w = nvars - 1; w > splitpos; --w )
    8101 {
    8102 SCIP_CALL( delCoefPos(scip, cons, w) );
    8103 ++(*nchgcoefs);
    8104 }
    8105 consdata->capacity -= maxactduetoclq;
    8106 assert(frontsum <= consdata->capacity);
    8107 ++(*nchgsides);
    8108
    8109 assert(w == splitpos);
    8110
    8111 /* renew weights pointer */
    8112 weights = consdata->weights;
    8113
    8114 /* division by greatest common divisor */
    8115 gcd = weights[w];
    8116 for( ; w >= 0 && gcd > 1; --w )
    8117 {
    8118 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
    8119 }
    8120
    8121 /* normalize if possible */
    8122 if( gcd > 1 )
    8123 {
    8124 for( w = splitpos; w >= 0; --w )
    8125 {
    8126 consdataChgWeight(consdata, w, weights[w]/gcd);
    8127 }
    8128 (*nchgcoefs) += nvars;
    8129
    8130 consdata->capacity /= gcd;
    8131 ++(*nchgsides);
    8132 }
    8133
    8134 /* free temporary memory */
    8135 SCIPfreeBufferArray(scip, &clqvars);
    8136
    8137 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8138 * weight must not be sorted by their index
    8139 */
    8140#ifndef NDEBUG
    8141 for( w = consdata->nvars - 1; w > 0; --w )
    8142 assert(weights[w] <= weights[w - 1]);
    8143#endif
    8144 }
    8145 }
    8146
    8147 /* free temporary memory */
    8148 SCIPfreeBufferArray(scip, &clqpart);
    8149 }
    8150
    8151 return SCIP_OKAY;
    8152}
    8153
    8154/* detect redundant variables which always fits into the knapsack
    8155 *
    8156 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
    8157 *
    8158 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
    8159 * => x4, x5 always fits into the knapsack, so we can delete them
    8160 *
    8161 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
    8162 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
    8163 */
    8164static
    8166 SCIP* scip, /**< SCIP data structure */
    8167 SCIP_CONS* cons, /**< knapsack constraint */
    8168 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    8169 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
    8170 int* nchgsides, /**< pointer to store the amount of changed sides */
    8171 int* naddconss /**< pointer to count number of added constraints */
    8172 )
    8173{
    8174 SCIP_CONSHDLRDATA* conshdlrdata;
    8175 SCIP_CONSDATA* consdata;
    8176 SCIP_VAR** vars;
    8177 SCIP_Longint* weights;
    8178 SCIP_Longint capacity;
    8179 SCIP_Longint sum;
    8180 int nvars;
    8181 int v;
    8182 int w;
    8183
    8184 assert(scip != NULL);
    8185 assert(cons != NULL);
    8186 assert(ndelconss != NULL);
    8187 assert(nchgcoefs != NULL);
    8188 assert(nchgsides != NULL);
    8189 assert(naddconss != NULL);
    8190
    8191 consdata = SCIPconsGetData(cons);
    8192 assert(consdata != NULL);
    8193 assert(consdata->nvars >= 2);
    8194 assert(consdata->weightsum > consdata->capacity);
    8195
    8196 vars = consdata->vars;
    8197 weights = consdata->weights;
    8198 nvars = consdata->nvars;
    8199 capacity = consdata->capacity;
    8200 sum = 0;
    8201
    8202 /* search for maximal fitting items */
    8203 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
    8204 sum += weights[v];
    8205
    8206 assert(v < nvars);
    8207
    8208 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
    8209 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == nvars - 1 )
    8210 {
    8211 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8212 assert(SCIPconsIsDeleted(cons));
    8213
    8214 return SCIP_OKAY;
    8215 }
    8216
    8217 if( v < nvars - 1 )
    8218 {
    8219 /* try to delete variables */
    8220 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
    8221 assert(consdata->nvars > 1);
    8222
    8223 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
    8224 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == consdata->nvars - 1 )
    8225 {
    8226 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8227 assert(SCIPconsIsDeleted(cons));
    8228 }
    8229
    8230 return SCIP_OKAY;
    8231 }
    8232
    8233 assert(vars == consdata->vars);
    8234 assert(weights == consdata->weights);
    8235 assert(nvars == consdata->nvars);
    8236 assert(capacity == consdata->capacity);
    8237
    8238 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    8239 assert(conshdlrdata != NULL);
    8240 /* calculate clique partition */
    8241 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
    8242
    8243 /* check for real existing cliques */
    8244 if( consdata->cliquepartition[v] < v )
    8245 {
    8246 SCIP_Longint sumfront;
    8247 SCIP_Longint maxactduetoclqfront;
    8248 int* clqpart;
    8249 int cliquenum;
    8250
    8251 sumfront = 0;
    8252 maxactduetoclqfront = 0;
    8253
    8254 clqpart = consdata->cliquepartition;
    8255 cliquenum = 0;
    8256
    8257 /* calculate maximal activity due to cliques */
    8258 for( w = 0; w < nvars; ++w )
    8259 {
    8260 assert(clqpart[w] >= 0 && clqpart[w] <= w);
    8261 if( clqpart[w] == cliquenum )
    8262 {
    8263 if( maxactduetoclqfront + weights[w] <= capacity )
    8264 {
    8265 maxactduetoclqfront += weights[w];
    8266 ++cliquenum;
    8267 }
    8268 else
    8269 break;
    8270 }
    8271 sumfront += weights[w];
    8272 }
    8273 assert(w >= v);
    8274
    8275 /* if all items fit, then delete the whole constraint but create clique constraints which led to this
    8276 * information
    8277 */
    8278 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0 && w == nvars )
    8279 {
    8280 SCIP_VAR** clqvars;
    8281 int nclqvars;
    8282 int c;
    8283 int ncliques;
    8284
    8285 assert(maxactduetoclqfront <= capacity);
    8286
    8287 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
    8288
    8289 ncliques = consdata->ncliques;
    8290
    8291 /* allocate temporary memory */
    8292 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
    8293
    8294 for( c = 0; c < ncliques; ++c )
    8295 {
    8296 nclqvars = 0;
    8297 for( w = 0; w < nvars; ++w )
    8298 {
    8299 if( clqpart[w] == c )
    8300 {
    8301 clqvars[nclqvars] = vars[w];
    8302 ++nclqvars;
    8303 }
    8304 }
    8305
    8306 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
    8307 if( nclqvars > 1 )
    8308 {
    8309 SCIP_CONS* cliquecons;
    8310 char name[SCIP_MAXSTRLEN];
    8311
    8312 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
    8313 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
    8317 SCIPconsIsStickingAtNode(cons)) );
    8318
    8319 /* add the special constraint to the problem */
    8320 SCIPdebugMsg(scip, " -> adding clique constraint: ");
    8321 SCIPdebugPrintCons(scip, cliquecons, NULL);
    8322 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    8323 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    8324 ++(*naddconss);
    8325 }
    8326 }
    8327
    8328 /* delete old constraint */
    8329 SCIP_CALL( SCIPdelCons(scip, cons) );
    8330 ++(*ndelconss);
    8331
    8332 SCIPfreeBufferArray(scip, &clqvars);
    8333
    8334 return SCIP_OKAY;
    8335 }
    8336
    8337 if( w > v && w < nvars - 1 )
    8338 {
    8339 /* try to delete variables */
    8340 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
    8341 }
    8342 }
    8343
    8344 return SCIP_OKAY;
    8345}
    8346
    8347/** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
    8348static
    8350 SCIP_CONS* cons, /**< knapsack constraint */
    8351 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    8352 int* nchgsides /**< pointer to count number of side changes */
    8353 )
    8354{
    8355 SCIP_CONSDATA* consdata;
    8356 SCIP_Longint gcd;
    8357 int i;
    8358
    8359 assert(nchgcoefs != NULL);
    8360 assert(nchgsides != NULL);
    8361 assert(!SCIPconsIsModifiable(cons));
    8362
    8363 consdata = SCIPconsGetData(cons);
    8364 assert(consdata != NULL);
    8365 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
    8366 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
    8367 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
    8368 assert(consdata->nvars >= 1);
    8369
    8370 /* sort items, because we can stop earlier if the smaller weights are evaluated first */
    8371 sortItems(consdata);
    8372
    8373 gcd = consdata->weights[consdata->nvars-1];
    8374 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
    8375 {
    8376 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
    8377 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
    8378
    8379 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
    8380 }
    8381
    8382 if( gcd >= 2 )
    8383 {
    8384 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
    8385
    8386 for( i = 0; i < consdata->nvars; ++i )
    8387 {
    8388 consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
    8389 }
    8390 consdata->capacity /= gcd;
    8391 (*nchgcoefs) += consdata->nvars;
    8392 (*nchgsides)++;
    8393
    8394 /* weight should still be sorted, because the reduction preserves this */
    8395#ifndef NDEBUG
    8396 for( i = consdata->nvars - 1; i > 0; --i )
    8397 assert(consdata->weights[i] <= consdata->weights[i - 1]);
    8398#endif
    8399 consdata->sorted = TRUE;
    8400 }
    8401}
    8402
    8403/** dual weights tightening for knapsack constraints
    8404 *
    8405 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
    8406 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
    8407 * constraint
    8408 *
    8409 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
    8410 * these are a minimal cover, then might reduce the weights and the capacity, e.g.
    8411 *
    8412 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
    8413 *
    8414 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
    8415 *
    8416 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
    8417 *
    8418 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
    8419 *
    8420 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
    8421 */
    8422static
    8424 SCIP* scip, /**< SCIP data structure */
    8425 SCIP_CONS* cons, /**< knapsack constraint */
    8426 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    8427 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
    8428 int* nchgsides, /**< pointer to store the amount of changed sides */
    8429 int* naddconss /**< pointer to count number of added constraints */
    8430 )
    8431{
    8432 SCIP_CONSDATA* consdata;
    8433 SCIP_Longint* weights;
    8434 SCIP_Longint dualcapacity;
    8435 SCIP_Longint reductionsum;
    8436 SCIP_Longint capacity;
    8437 SCIP_Longint exceedsum;
    8438 int oldnchgcoefs;
    8439 int nvars;
    8440 int vbig;
    8441 int v;
    8442 int w;
    8443#ifndef NDEBUG
    8444 int oldnchgsides;
    8445#endif
    8446
    8447 assert(scip != NULL);
    8448 assert(cons != NULL);
    8449 assert(ndelconss != NULL);
    8450 assert(nchgcoefs != NULL);
    8451 assert(nchgsides != NULL);
    8452 assert(naddconss != NULL);
    8453
    8454 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
    8455 return SCIP_OKAY;
    8456
    8457#ifndef NDEBUG
    8458 oldnchgsides = *nchgsides;
    8459#endif
    8460
    8461 consdata = SCIPconsGetData(cons);
    8462 assert(consdata != NULL);
    8463 assert(consdata->weightsum > consdata->capacity);
    8464 assert(consdata->nvars >= 2);
    8465 assert(consdata->sorted);
    8466
    8467 /* constraint should be merged */
    8468 assert(consdata->merged);
    8469
    8470 nvars = consdata->nvars;
    8471 weights = consdata->weights;
    8472 capacity = consdata->capacity;
    8473
    8474 oldnchgcoefs = *nchgcoefs;
    8475
    8476 /* case 1. */
    8477 if( weights[nvars - 1] + weights[nvars - 2] > capacity )
    8478 {
    8479 SCIP_CONS* newcons;
    8480
    8481 /* two variable are enough to exceed the constraint, so we can update it to a set-packing
    8482 *
    8483 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
    8484 */
    8485 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
    8486
    8487 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
    8491 SCIPconsIsStickingAtNode(cons)) );
    8492
    8493 /* add the upgraded constraint to the problem */
    8494 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
    8495 ++(*naddconss);
    8496
    8497 /* remove the underlying constraint from the problem */
    8498 SCIP_CALL( SCIPdelCons(scip, cons) );
    8499 ++(*ndelconss);
    8500
    8501 return SCIP_OKAY;
    8502 }
    8503
    8504 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
    8505 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
    8506 {
    8507 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8508 assert(SCIPconsIsDeleted(cons));
    8509
    8510 return SCIP_OKAY;
    8511 }
    8512
    8513 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
    8514 /* @todo might be changed/removed when improving the coeffcients tightening */
    8515 if( consdata->weightsum - capacity > weights[0] + weights[1] )
    8516 return SCIP_OKAY;
    8517
    8518 /* case 2. */
    8519
    8520 v = 0;
    8521
    8522 /* @todo generalize the following algorithm for several parts of the knapsack
    8523 *
    8524 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
    8525 * variables each combination is a minimal cover, some examples
    8526 *
    8527 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
    8528 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
    8529 * <=> x1 + x2 + x3 + x4 + x5 <= 3
    8530 *
    8531 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
    8532 *
    8533 */
    8534
    8535 /* determine big weights that fit only by itself */
    8536 while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
    8537 ++v;
    8538
    8539 vbig = v;
    8540 assert(vbig < nvars - 1);
    8541 exceedsum = 0;
    8542
    8543 /* determine the amount needed to exceed the capacity */
    8544 while( v < nvars && exceedsum <= capacity )
    8545 {
    8546 exceedsum += weights[v];
    8547 ++v;
    8548 }
    8549
    8550 /* if we exceeded the capacity we might reduce the weights */
    8551 if( exceedsum > capacity )
    8552 {
    8553 assert(vbig > 0 || v < nvars);
    8554
    8555 /* all small weights were needed to exceed the capacity */
    8556 if( v == nvars )
    8557 {
    8558 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
    8559 assert(newweight > 0);
    8560
    8561 /* reduce big weights */
    8562 for( v = 0; v < vbig; ++v )
    8563 {
    8564 if( weights[v] > newweight )
    8565 {
    8566 consdataChgWeight(consdata, v, newweight);
    8567 ++(*nchgcoefs);
    8568 }
    8569 }
    8570
    8571 /* reduce small weights */
    8572 for( ; v < nvars; ++v )
    8573 {
    8574 if( weights[v] > 1 )
    8575 {
    8576 consdataChgWeight(consdata, v, 1LL);
    8577 ++(*nchgcoefs);
    8578 }
    8579 }
    8580
    8581 consdata->capacity = newweight;
    8582
    8583 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8584 * weight must not be sorted by their index
    8585 */
    8586#ifndef NDEBUG
    8587 for( v = nvars - 1; v > 0; --v )
    8588 assert(weights[v] <= weights[v-1]);
    8589#endif
    8590
    8591 return SCIP_OKAY;
    8592 }
    8593 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
    8594 * small weights
    8595 */
    8596 else
    8597 {
    8598 SCIP_Longint exceedsumback = 0;
    8599 int nexceed = v - vbig;
    8600
    8601 assert(nexceed > 1);
    8602
    8603 /* determine weightsum of the same amount as before but of the smallest weight */
    8604 for( w = nvars - 1; w >= nvars - nexceed; --w )
    8605 exceedsumback += weights[w];
    8606
    8607 assert(w >= 0);
    8608
    8609 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
    8610 * combinations of all small weights
    8611 */
    8612 if( exceedsumback > capacity )
    8613 {
    8614 SCIP_Longint newweight = nexceed - 1;
    8615
    8616 /* taking out the smallest element needs to fit */
    8617 assert(exceedsumback - weights[nvars - 1] <= capacity);
    8618
    8619 /* reduce big weights */
    8620 for( v = 0; v < vbig; ++v )
    8621 {
    8622 if( weights[v] > newweight )
    8623 {
    8624 consdataChgWeight(consdata, v, newweight);
    8625 ++(*nchgcoefs);
    8626 }
    8627 }
    8628
    8629 /* reduce small weights */
    8630 for( ; v < nvars; ++v )
    8631 {
    8632 if( weights[v] > 1 )
    8633 {
    8634 consdataChgWeight(consdata, v, 1LL);
    8635 ++(*nchgcoefs);
    8636 }
    8637 }
    8638
    8639 consdata->capacity = newweight;
    8640
    8641 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8642 * weight must not be sorted by their index
    8643 */
    8644#ifndef NDEBUG
    8645 for( v = nvars - 1; v > 0; --v )
    8646 assert(weights[v] <= weights[v-1]);
    8647#endif
    8648 return SCIP_OKAY;
    8649 }
    8650 }
    8651 }
    8652 else
    8653 {
    8654 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
    8655 * not happen here
    8656 */
    8657 assert(vbig > 0 && vbig < nvars);
    8658
    8659 /* either choose a big coefficients or all other variables
    8660 *
    8661 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
    8662 *
    8663 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
    8664 * constraint to
    8665 *
    8666 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
    8667 */
    8668
    8669 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
    8670 {
    8671 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
    8672#ifndef NDEBUG
    8673 SCIP_Longint resweightsum = consdata->weightsum;
    8674
    8675 for( v = 0; v < vbig; ++v )
    8676 resweightsum -= weights[v];
    8677
    8678 assert(exceedsum == resweightsum);
    8679#endif
    8680 assert(newweight > 0);
    8681
    8682 /* reduce big weights */
    8683 for( v = 0; v < vbig; ++v )
    8684 {
    8685 if( weights[v] > newweight )
    8686 {
    8687 consdataChgWeight(consdata, v, newweight);
    8688 ++(*nchgcoefs);
    8689 }
    8690 }
    8691
    8692 /* reduce small weights */
    8693 for( ; v < nvars; ++v )
    8694 {
    8695 if( weights[v] > 1 )
    8696 {
    8697 consdataChgWeight(consdata, v, 1LL);
    8698 ++(*nchgcoefs);
    8699 }
    8700 }
    8701
    8702 consdata->capacity = newweight;
    8703
    8704 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8705 * weight must not be sorted by their index
    8706 */
    8707#ifndef NDEBUG
    8708 for( v = nvars - 1; v > 0; --v )
    8709 assert(weights[v] <= weights[v-1]);
    8710#endif
    8711 return SCIP_OKAY;
    8712 }
    8713 }
    8714
    8715 /* case 3. */
    8716
    8717 dualcapacity = consdata->weightsum - capacity;
    8718 reductionsum = 0;
    8719 v = 0;
    8720
    8721 /* reduce big weights
    8722 *
    8723 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
    8724 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
    8725 * <=> x0 + x1 + x2 + x3 <= 3
    8726 */
    8727 while( weights[v] > dualcapacity )
    8728 {
    8729 reductionsum += (weights[v] - dualcapacity);
    8730 consdataChgWeight(consdata, v, dualcapacity);
    8731 ++v;
    8732 assert(v < nvars);
    8733 }
    8734 (*nchgcoefs) += v;
    8735
    8736 /* skip weights equal to the dualcapacity, because we cannot change them */
    8737 while( v < nvars && weights[v] == dualcapacity )
    8738 ++v;
    8739
    8740 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
    8741 * after a possible removal of the last, redundant item
    8742 *
    8743 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
    8744 */
    8745 if( v >= nvars - 1 )
    8746 {
    8747 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
    8748 if( v == nvars - 1 )
    8749 {
    8750 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
    8751 }
    8752 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8753 assert(SCIPconsIsDeleted(cons));
    8754
    8755 return SCIP_OKAY;
    8756 }
    8757 /* at least two items with weight smaller than the dual capacity */
    8758 else
    8759 {
    8760 /* @todo generalize the following algorithm for more than two variables */
    8761
    8762 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
    8763 {
    8764 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
    8765 * coefficients) of all or two variables of the rest
    8766 *
    8767 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
    8768 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
    8769 * <=> 2x1 + 2x2 + x3 + x4 <= 4
    8770 *
    8771 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
    8772 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
    8773 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
    8774 *
    8775 */
    8776 if( v > 0 && weights[nvars - 2] > 1 )
    8777 {
    8778 int ncoefchg = 0;
    8779
    8780 /* reduce all bigger weights */
    8781 for( w = 0; w < v; ++w )
    8782 {
    8783 if( weights[w] > 2 )
    8784 {
    8785 consdataChgWeight(consdata, w, 2LL);
    8786 ++ncoefchg;
    8787 }
    8788 else
    8789 {
    8790 assert(weights[0] == 2);
    8791 assert(weights[v - 1] == 2);
    8792 break;
    8793 }
    8794 }
    8795
    8796 /* reduce all smaller weights */
    8797 for( w = v; w < nvars; ++w )
    8798 {
    8799 if( weights[w] > 1 )
    8800 {
    8801 consdataChgWeight(consdata, w, 1LL);
    8802 ++ncoefchg;
    8803 }
    8804 }
    8805 assert(ncoefchg > 0);
    8806
    8807 (*nchgcoefs) += ncoefchg;
    8808
    8809 /* correct the capacity */
    8810 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
    8811 assert(consdata->capacity > 0);
    8812 assert(weights[0] <= consdata->capacity);
    8813 assert(consdata->weightsum > consdata->capacity);
    8814 /* reset the reductionsum */
    8815 reductionsum = 0;
    8816 }
    8817 else if( v == 0 )
    8818 {
    8819 assert(weights[nvars - 2] == 1);
    8820 }
    8821 }
    8822 else
    8823 {
    8824 SCIP_Longint minweight = weights[nvars - 1];
    8825 SCIP_Longint newweight = dualcapacity - minweight;
    8826 SCIP_Longint restsumweights = 0;
    8827 SCIP_Longint sumcoef;
    8828 SCIP_Bool sumcoefcase = FALSE;
    8829 int startv = v;
    8830 int end;
    8831 int k;
    8832
    8833 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
    8834
    8835 /* reduce big weights of pairs that exceed the dualcapacity
    8836 *
    8837 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
    8838 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
    8839 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
    8840 */
    8841 while( weights[v] > newweight )
    8842 {
    8843 reductionsum += (weights[v] - newweight);
    8844 consdataChgWeight(consdata, v, newweight);
    8845 ++v;
    8846 assert(v < nvars);
    8847 }
    8848 (*nchgcoefs) += (v - startv);
    8849
    8850 /* skip equal weights */
    8851 while( weights[v] == newweight )
    8852 ++v;
    8853
    8854 if( v > 0 )
    8855 {
    8856 for( w = v; w < nvars; ++w )
    8857 restsumweights += weights[w];
    8858 }
    8859 else
    8860 restsumweights = consdata->weightsum;
    8861
    8862 if( restsumweights < dualcapacity )
    8863 {
    8864 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
    8865 *
    8866 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
    8867 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
    8868 */
    8869 if( startv == v )
    8870 {
    8871 /* remove redundant variables */
    8872 for( w = nvars - 1; w >= v; --w )
    8873 {
    8874 SCIP_CALL( delCoefPos(scip, cons, v) );
    8875 ++(*nchgcoefs);
    8876 }
    8877
    8878#ifndef NDEBUG
    8879 /* each coefficients should exceed the dualcapacity by itself */
    8880 for( ; w >= 0; --w )
    8881 assert(weights[w] == dualcapacity);
    8882#endif
    8883 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
    8884 * upgrade this constraint
    8885 */
    8886 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8887 assert(SCIPconsIsDeleted(cons));
    8888
    8889 return SCIP_OKAY;
    8890 }
    8891
    8892 /* special case where we have three different coefficient types
    8893 *
    8894 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
    8895 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
    8896 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
    8897 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
    8898 */
    8899 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
    8900 {
    8901 SCIP_Longint newcap;
    8902
    8903 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
    8904 for( w = nvars - 1; w >= v; --w )
    8905 {
    8906 if( weights[w] > 1 )
    8907 {
    8908 consdataChgWeight(consdata, w, 1LL);
    8909 ++(*nchgcoefs);
    8910 }
    8911 }
    8912
    8913 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
    8914 * dualcapacity
    8915 */
    8916 newweight = (SCIP_Longint)nvars - v;
    8917 assert(newweight > 1);
    8918 for( ; w >= startv; --w )
    8919 {
    8920 if( weights[w] > newweight )
    8921 {
    8922 consdataChgWeight(consdata, w, newweight);
    8923 ++(*nchgcoefs);
    8924 }
    8925 else
    8926 assert(weights[w] == newweight);
    8927 }
    8928
    8929 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
    8930 ++newweight;
    8931 assert(newweight > 2);
    8932 for( ; w >= 0; --w )
    8933 {
    8934 if( weights[w] > newweight )
    8935 {
    8936 consdataChgWeight(consdata, w, newweight);
    8937 ++(*nchgcoefs);
    8938 }
    8939 else
    8940 assert(weights[w] == newweight);
    8941 }
    8942
    8943 /* update the capacity */
    8944 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
    8945 if( consdata->capacity > newcap )
    8946 {
    8947 consdata->capacity = newcap;
    8948 ++(*nchgsides);
    8949 }
    8950 else
    8951 assert(consdata->capacity == newcap);
    8952 }
    8953 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
    8954
    8955 /* the new dualcapacity should still be equal to the (nvars - v + 1) */
    8956 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
    8957
    8958 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8959 * weight must not be sorted by their index
    8960 */
    8961#ifndef NDEBUG
    8962 for( w = nvars - 1; w > 0; --w )
    8963 assert(weights[w] <= weights[w - 1]);
    8964#endif
    8965 return SCIP_OKAY;
    8966 }
    8967
    8968 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
    8969 end = nvars - 2;
    8970 while( end >= 0 && weights[end] == weights[end + 1] )
    8971 {
    8972 assert(end >= v);
    8973 --end;
    8974 }
    8975
    8976 if( v >= end )
    8977 goto TERMINATE;
    8978
    8979 end = nvars - 2;
    8980
    8981 /* can we stop early, another special reduction case might exist */
    8982 if( 2 * weights[end] > dualcapacity )
    8983 {
    8984 restsumweights = 0;
    8985
    8986 /* determine capacity of the small items */
    8987 for( w = end + 1; w < nvars; ++w )
    8988 restsumweights += weights[w];
    8989
    8990 if( restsumweights * 2 <= dualcapacity )
    8991 {
    8992 /* check for further posssible reductions in the middle */
    8993 while( v < end && restsumweights + weights[v] >= dualcapacity )
    8994 ++v;
    8995
    8996 if( v >= end )
    8997 goto TERMINATE;
    8998
    8999 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
    9000 if( (dualcapacity & 1) == 0 )
    9001 {
    9002 newweight = dualcapacity / 2;
    9003
    9004 /* set all middle coefficients */
    9005 for( ; v <= end; ++v )
    9006 {
    9007 if( weights[v] > newweight )
    9008 {
    9009 reductionsum += (weights[v] - newweight);
    9010 consdataChgWeight(consdata, v, newweight);
    9011 ++(*nchgcoefs);
    9012 }
    9013 }
    9014 }
    9015 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
    9016 * other coefficients by 2
    9017 */
    9018 else
    9019 {
    9020 /* correct the reductionsum */
    9021 reductionsum *= 2;
    9022
    9023 /* multiply big coefficients by 2 */
    9024 for( w = 0; w < v; ++w )
    9025 {
    9026 consdataChgWeight(consdata, w, weights[w] * 2);
    9027 }
    9028
    9029 newweight = dualcapacity;
    9030 /* set all middle coefficients */
    9031 for( ; v <= end; ++v )
    9032 {
    9033 reductionsum += (2 * weights[v] - newweight);
    9034 consdataChgWeight(consdata, v, newweight);
    9035 }
    9036
    9037 /* multiply small coefficients by 2 */
    9038 for( w = end + 1; w < nvars; ++w )
    9039 {
    9040 consdataChgWeight(consdata, w, weights[w] * 2);
    9041 }
    9042 (*nchgcoefs) += nvars;
    9043
    9044 dualcapacity *= 2;
    9045 consdata->capacity *= 2;
    9046 ++(*nchgsides);
    9047 }
    9048 }
    9049
    9050 goto TERMINATE;
    9051 }
    9052
    9053 /* further reductions using the next possible coefficient sum
    9054 *
    9055 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
    9056 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
    9057 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
    9058 */
    9059 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
    9060 for( k = 0; k < 4; ++k )
    9061 {
    9062 /* determine next minimal coefficient sum */
    9063 switch( k )
    9064 {
    9065 case 0:
    9066 sumcoef = weights[nvars - 1] + weights[nvars - 2];
    9067 break;
    9068 case 1:
    9069 assert(nvars >= 3);
    9070 sumcoef = weights[nvars - 1] + weights[nvars - 3];
    9071 break;
    9072 case 2:
    9073 assert(nvars >= 4);
    9074 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
    9075 {
    9076 sumcoefcase = TRUE;
    9077 sumcoef = weights[nvars - 1] + weights[nvars - 4];
    9078 }
    9079 else
    9080 {
    9081 sumcoefcase = FALSE;
    9082 sumcoef = weights[nvars - 2] + weights[nvars - 3];
    9083 }
    9084 break;
    9085 case 3:
    9086 assert(nvars >= 5);
    9087 if( sumcoefcase )
    9088 {
    9089 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
    9090 }
    9091 else
    9092 {
    9093 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
    9094 }
    9095 break;
    9096 default:
    9097 return SCIP_ERROR;
    9098 }
    9099
    9100 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
    9101 minweight = weights[end];
    9102 while( minweight <= sumcoef )
    9103 {
    9104 newweight = dualcapacity - minweight;
    9105 startv = v;
    9106 assert(v < nvars);
    9107
    9108 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
    9109 /* shrink big coefficients */
    9110 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
    9111 {
    9112 reductionsum += (weights[v] - newweight);
    9113 consdataChgWeight(consdata, v, newweight);
    9114 ++v;
    9115 assert(v < nvars);
    9116 }
    9117 (*nchgcoefs) += (v - startv);
    9118
    9119 /* skip unchangable weights */
    9120 while( weights[v] + minweight == dualcapacity )
    9121 {
    9122 assert(v < nvars);
    9123 ++v;
    9124 }
    9125
    9126 --end;
    9127 /* skip same end weights */
    9128 while( end >= 0 && weights[end] == weights[end + 1] )
    9129 --end;
    9130
    9131 if( v >= end )
    9132 goto TERMINATE;
    9133
    9134 minweight = weights[end];
    9135 }
    9136
    9137 if( v >= end )
    9138 goto TERMINATE;
    9139
    9140 /* now check if a combination of small coefficients allows us to tighten big coefficients further */
    9141 if( sumcoef < minweight )
    9142 {
    9143 minweight = sumcoef;
    9144 newweight = dualcapacity - minweight;
    9145 startv = v;
    9146 assert(v < nvars);
    9147
    9148 /* shrink big coefficients */
    9149 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
    9150 {
    9151 reductionsum += (weights[v] - newweight);
    9152 consdataChgWeight(consdata, v, newweight);
    9153 ++v;
    9154 assert(v < nvars);
    9155 }
    9156 (*nchgcoefs) += (v - startv);
    9157
    9158 /* skip unchangable weights */
    9159 while( weights[v] + minweight == dualcapacity )
    9160 {
    9161 assert(v < nvars);
    9162 ++v;
    9163 }
    9164 }
    9165
    9166 if( v >= end )
    9167 goto TERMINATE;
    9168
    9169 /* can we stop early, another special reduction case might exist */
    9170 if( 2 * weights[end] > dualcapacity )
    9171 {
    9172 restsumweights = 0;
    9173
    9174 /* determine capacity of the small items */
    9175 for( w = end + 1; w < nvars; ++w )
    9176 restsumweights += weights[w];
    9177
    9178 if( restsumweights * 2 <= dualcapacity )
    9179 {
    9180 /* check for further posssible reductions in the middle */
    9181 while( v < end && restsumweights + weights[v] >= dualcapacity )
    9182 ++v;
    9183
    9184 if( v >= end )
    9185 goto TERMINATE;
    9186
    9187 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
    9188 if( (dualcapacity & 1) == 0 )
    9189 {
    9190 newweight = dualcapacity / 2;
    9191
    9192 /* set all middle coefficients */
    9193 for( ; v <= end; ++v )
    9194 {
    9195 if( weights[v] > newweight )
    9196 {
    9197 reductionsum += (weights[v] - newweight);
    9198 consdataChgWeight(consdata, v, newweight);
    9199 ++(*nchgcoefs);
    9200 }
    9201 }
    9202 }
    9203 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
    9204 * other coefficients by 2
    9205 */
    9206 else
    9207 {
    9208 /* correct the reductionsum */
    9209 reductionsum *= 2;
    9210
    9211 /* multiply big coefficients by 2 */
    9212 for( w = 0; w < v; ++w )
    9213 {
    9214 consdataChgWeight(consdata, w, weights[w] * 2);
    9215 }
    9216
    9217 newweight = dualcapacity;
    9218 /* set all middle coefficients */
    9219 for( ; v <= end; ++v )
    9220 {
    9221 reductionsum += (2 * weights[v] - newweight);
    9222 consdataChgWeight(consdata, v, newweight);
    9223 }
    9224
    9225 /* multiply small coefficients by 2 */
    9226 for( w = end + 1; w < nvars; ++w )
    9227 {
    9228 consdataChgWeight(consdata, w, weights[w] * 2);
    9229 }
    9230 (*nchgcoefs) += nvars;
    9231
    9232 dualcapacity *= 2;
    9233 consdata->capacity *= 2;
    9234 ++(*nchgsides);
    9235 }
    9236 }
    9237
    9238 goto TERMINATE;
    9239 }
    9240
    9241 /* cannot tighten any further */
    9242 if( 2 * sumcoef > dualcapacity )
    9243 goto TERMINATE;
    9244 }
    9245 }
    9246 }
    9247
    9248 TERMINATE:
    9249 /* correct capacity */
    9250 if( reductionsum > 0 )
    9251 {
    9252 assert(v > 0);
    9253
    9254 consdata->capacity -= reductionsum;
    9255 ++(*nchgsides);
    9256
    9257 assert(consdata->weightsum - dualcapacity == consdata->capacity);
    9258 }
    9259 assert(weights[0] <= consdata->capacity);
    9260
    9261 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    9262 * weight must not be sorted by their index
    9263 */
    9264#ifndef NDEBUG
    9265 for( w = nvars - 1; w > 0; --w )
    9266 assert(weights[w] <= weights[w - 1]);
    9267#endif
    9268
    9269 if( oldnchgcoefs < *nchgcoefs )
    9270 {
    9271 assert(!SCIPconsIsDeleted(cons));
    9272
    9273 /* it might be that we can divide the weights by their greatest common divisor */
    9274 normalizeWeights(cons, nchgcoefs, nchgsides);
    9275 }
    9276 else
    9277 {
    9278 assert(oldnchgcoefs == *nchgcoefs);
    9279 assert(oldnchgsides == *nchgsides);
    9280 }
    9281
    9282 return SCIP_OKAY;
    9283}
    9284
    9285
    9286/** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
    9287static
    9289 SCIP* scip, /**< SCIP data structure */
    9290 SCIP_CONS* cons, /**< knapsack constraint */
    9291 int* nfixedvars, /**< pointer to store the amount of fixed variables */
    9292 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    9293 int* nchgcoefs /**< pointer to store the amount of changed coefficients */
    9294 )
    9295{
    9296 SCIP_VAR** vars;
    9297 SCIP_CONSDATA* consdata;
    9298 SCIP_Longint* weights;
    9299 SCIP_Longint capacity;
    9300 SCIP_Bool infeasible;
    9301 SCIP_Bool fixed;
    9302 int nvars;
    9303 int v;
    9304
    9305 assert(scip != NULL);
    9306 assert(cons != NULL);
    9307 assert(nfixedvars != NULL);
    9308 assert(ndelconss != NULL);
    9309 assert(nchgcoefs != NULL);
    9310
    9311 consdata = SCIPconsGetData(cons);
    9312 assert(consdata != NULL);
    9313
    9314 nvars = consdata->nvars;
    9315
    9316 /* no variables left, then delete constraint */
    9317 if( nvars == 0 )
    9318 {
    9319 assert(consdata->capacity >= 0);
    9320
    9321 SCIP_CALL( SCIPdelCons(scip, cons) );
    9322 ++(*ndelconss);
    9323
    9324 return SCIP_OKAY;
    9325 }
    9326
    9327 /* sort items */
    9328 sortItems(consdata);
    9329
    9330 vars = consdata->vars;
    9331 weights = consdata->weights;
    9332 capacity = consdata->capacity;
    9333 v = 0;
    9334
    9335 /* check for weights bigger than the capacity */
    9336 while( v < nvars && weights[v] > capacity )
    9337 {
    9338 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
    9339 assert(!infeasible);
    9340
    9341 if( fixed )
    9342 ++(*nfixedvars);
    9343
    9344 ++v;
    9345 }
    9346
    9347 /* if we fixed at least one variable we need to delete them from the constraint */
    9348 if( v > 0 )
    9349 {
    9350 if( v == nvars )
    9351 {
    9352 SCIP_CALL( SCIPdelCons(scip, cons) );
    9353 ++(*ndelconss);
    9354
    9355 return SCIP_OKAY;
    9356 }
    9357
    9358 /* delete all position from back to front */
    9359 for( --v; v >= 0; --v )
    9360 {
    9361 SCIP_CALL( delCoefPos(scip, cons, v) );
    9362 ++(*nchgcoefs);
    9363 }
    9364
    9365 /* sort items again because of deletion */
    9366 sortItems(consdata);
    9367 assert(vars == consdata->vars);
    9368 assert(weights == consdata->weights);
    9369 }
    9370 assert(consdata->sorted);
    9371 assert(weights[0] <= capacity);
    9372
    9373 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
    9374 {
    9375 SCIP_CALL( SCIPdelCons(scip, cons) );
    9376 ++(*ndelconss);
    9377 }
    9378
    9379 return SCIP_OKAY;
    9380}
    9381
    9382
    9383/** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
    9384 *
    9385 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
    9386 *
    9387 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
    9388 *
    9389 * the above constraint can be changed to
    9390 *
    9391 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
    9392 *
    9393 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
    9394 *
    9395 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
    9396 *
    9397 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
    9398 * constraint further, e.g.
    9399 *
    9400 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
    9401 * => 2x1 + x2 + x3 + x4 <= 2
    9402 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
    9403 */
    9404static
    9406 SCIP* scip, /**< SCIP data structure */
    9407 SCIP_CONS* cons, /**< knapsack constraint */
    9408 int* nfixedvars, /**< pointer to store the amount of fixed variables */
    9409 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    9410 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
    9411 int* nchgsides, /**< pointer to store the amount of changed sides */
    9412 int* naddconss, /**< pointer to count number of added constraints */
    9413 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
    9414 )
    9415{
    9416 SCIP_VAR** vars;
    9417 SCIP_CONSDATA* consdata;
    9418 SCIP_Longint* weights;
    9419 SCIP_Longint restweight;
    9420 SCIP_Longint newweight;
    9421 SCIP_Longint weight;
    9422 SCIP_Longint oldgcd;
    9423 SCIP_Longint rest;
    9424 SCIP_Longint gcd;
    9425 int oldnchgcoefs; /* cppcheck-suppress unassignedVariable */
    9426 int oldnchgsides; /* cppcheck-suppress unassignedVariable */
    9427 int candpos;
    9428 int candpos2;
    9429 int offsetv;
    9430 int nvars;
    9431 int v;
    9432
    9433 assert(scip != NULL);
    9434 assert(cons != NULL);
    9435 assert(nfixedvars != NULL);
    9436 assert(ndelconss != NULL);
    9437 assert(nchgcoefs != NULL);
    9438 assert(nchgsides != NULL);
    9439 assert(naddconss != NULL);
    9440 assert(cutoff != NULL);
    9441 assert(!SCIPconsIsModifiable(cons));
    9442
    9443 consdata = SCIPconsGetData(cons);
    9444 assert( consdata != NULL );
    9445
    9446 *cutoff = FALSE;
    9447
    9448 /* remove double enties and also combinations of active and negated variables */
    9449 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    9450 assert(consdata->merged);
    9451 if( *cutoff )
    9452 return SCIP_OKAY;
    9453
    9454 assert(consdata->capacity >= 0);
    9455
    9456 /* fix variables with big coefficients and remove redundant constraints, sort weights */
    9457 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
    9458
    9459 if( SCIPconsIsDeleted(cons) )
    9460 return SCIP_OKAY;
    9461
    9462 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
    9463 {
    9464 /* 1. dual weights tightening */
    9465 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
    9466
    9467 if( SCIPconsIsDeleted(cons) )
    9468 return SCIP_OKAY;
    9469 /* 2. delete redundant variables */
    9470 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
    9471
    9472 if( SCIPconsIsDeleted(cons) )
    9473 return SCIP_OKAY;
    9474 }
    9475
    9476 weights = consdata->weights;
    9477 nvars = consdata->nvars;
    9478
    9479#ifndef NDEBUG
    9480 /* constraint might not be sorted, but the weights are already sorted */
    9481 for( v = nvars - 1; v > 0; --v )
    9482 assert(weights[v] <= weights[v-1]);
    9483#endif
    9484
    9485 /* determine greatest common divisor */
    9486 gcd = weights[nvars - 1];
    9487 for( v = nvars - 2; v >= 0 && gcd > 1; --v )
    9488 {
    9489 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
    9490 }
    9491
    9492 /* divide the constraint by their greatest common divisor */
    9493 if( gcd >= 2 )
    9494 {
    9495 for( v = nvars - 1; v >= 0; --v )
    9496 {
    9497 consdataChgWeight(consdata, v, weights[v]/gcd);
    9498 }
    9499 (*nchgcoefs) += nvars;
    9500
    9501 consdata->capacity /= gcd;
    9502 (*nchgsides)++;
    9503 }
    9504 assert(consdata->nvars == nvars);
    9505
    9506 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
    9507 * must not be sorted by their index
    9508 */
    9509#ifndef NDEBUG
    9510 for( v = nvars - 1; v > 0; --v )
    9511 assert(weights[v] <= weights[v-1]);
    9512#endif
    9513
    9514 /* 3. start gcd procedure for all variables */
    9515 do
    9516 {
    9517 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
    9518 SCIPdebug( oldnchgsides = *nchgsides; )
    9519
    9520 vars = consdata->vars;
    9521 weights = consdata->weights;
    9522 nvars = consdata->nvars;
    9523
    9524 /* stop if we have two coefficients which are one in absolute value */
    9525 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
    9526 return SCIP_OKAY;
    9527
    9528 v = 0;
    9529 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
    9530 * gcd
    9531 */
    9532 while( weights[v] == consdata->capacity )
    9533 {
    9534 ++v;
    9535 assert(v < nvars);
    9536 }
    9537
    9538 /* all but one variable are as big as the capacity, this is handled elsewhere */
    9539 if( v == nvars - 1 )
    9540 return SCIP_OKAY;
    9541
    9542 offsetv = v;
    9543
    9544 gcd = -1;
    9545 candpos = -1;
    9546 candpos2 = -1;
    9547
    9548 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
    9549 * change the coefficient
    9550 */
    9551 for( v = nvars - 1; v >= offsetv; --v )
    9552 {
    9553 weight = weights[v];
    9554 assert(weight >= 1);
    9555
    9556 oldgcd = gcd;
    9557
    9558 if( gcd == -1 )
    9559 {
    9560 gcd = weights[v];
    9561 assert(gcd >= 1);
    9562 }
    9563 else
    9564 {
    9565 /* calculate greatest common divisor for all variables */
    9566 gcd = SCIPcalcGreComDiv(gcd, weight);
    9567 }
    9568
    9569 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
    9570 * can terminate
    9571 */
    9572 if( gcd == 1 )
    9573 {
    9574 /* found candidate */
    9575 if( candpos == -1 )
    9576 {
    9577 gcd = oldgcd;
    9578 candpos = v;
    9579
    9580 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
    9581 if( v == nvars - 2 )
    9582 candpos2 = v + 1;
    9583 }
    9584 /* two different variables lead to a gcd of one, so we cannot change a coefficient */
    9585 else
    9586 {
    9587 if( candpos == v + 1 && candpos2 == v + 2 )
    9588 {
    9589 assert(candpos2 == nvars - 1);
    9590
    9591 /* take new candidates */
    9592 candpos = candpos2;
    9593
    9594 /* recalculate gcd from scratch */
    9595 gcd = weights[v+1];
    9596 assert(gcd >= 1);
    9597
    9598 /* calculate greatest common divisor for variables */
    9599 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
    9600 if( gcd == 1 )
    9601 return SCIP_OKAY;
    9602 }
    9603 else
    9604 /* cannot determine a possible coefficient for reduction */
    9605 return SCIP_OKAY;
    9606 }
    9607 }
    9608 }
    9609 assert(gcd >= 2);
    9610
    9611 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
    9612 * further
    9613 */
    9614 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
    9615
    9616 /* determine the remainder of the capacity and the gcd */
    9617 rest = consdata->capacity % gcd;
    9618 assert(rest >= 0);
    9619 assert(rest < gcd);
    9620
    9621 if( candpos == -1 )
    9622 {
    9623 /* we assume that the constraint was normalized */
    9624 assert(rest > 0);
    9625
    9626 /* replace old with new capacity */
    9627 consdata->capacity -= rest;
    9628 ++(*nchgsides);
    9629
    9630 /* replace old big coefficients with new capacity */
    9631 for( v = 0; v < offsetv; ++v )
    9632 {
    9633 consdataChgWeight(consdata, v, consdata->capacity);
    9634 }
    9635
    9636 *nchgcoefs += offsetv;
    9637 goto CONTINUE;
    9638 }
    9639
    9640 /* determine the remainder of the coefficient candidate and the gcd */
    9641 restweight = weights[candpos] % gcd;
    9642 assert(restweight >= 1);
    9643 assert(restweight < gcd);
    9644
    9645 /* calculate new coefficient */
    9646 if( restweight > rest )
    9647 newweight = weights[candpos] - restweight + gcd;
    9648 else
    9649 newweight = weights[candpos] - restweight;
    9650
    9651 assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
    9652
    9653 SCIPdebugMsg(scip, "gcd = %" SCIP_LONGINT_FORMAT ", rest = %" SCIP_LONGINT_FORMAT ", restweight = %" SCIP_LONGINT_FORMAT "; possible new weight of variable <%s> %" SCIP_LONGINT_FORMAT ", possible new capacity %" SCIP_LONGINT_FORMAT ", offset of coefficients as big as capacity %d\n", gcd, rest, restweight, SCIPvarGetName(vars[candpos]), newweight, consdata->capacity - rest, offsetv);
    9654
    9655 /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
    9656 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
    9657 */
    9658 if( newweight == 0 && offsetv > 0 )
    9659 return SCIP_OKAY;
    9660
    9661 if( rest > 0 )
    9662 {
    9663 /* replace old with new capacity */
    9664 consdata->capacity -= rest;
    9665 ++(*nchgsides);
    9666
    9667 /* replace old big coefficients with new capacity */
    9668 for( v = 0; v < offsetv; ++v )
    9669 {
    9670 consdataChgWeight(consdata, v, consdata->capacity);
    9671 }
    9672
    9673 *nchgcoefs += offsetv;
    9674 }
    9675
    9676 if( newweight == 0 )
    9677 {
    9678 /* delete redundant coefficient */
    9679 SCIP_CALL( delCoefPos(scip, cons, candpos) );
    9680 assert(consdata->nvars == nvars - 1);
    9681 --nvars;
    9682 }
    9683 else
    9684 {
    9685 /* replace old with new coefficient */
    9686 consdataChgWeight(consdata, candpos, newweight);
    9687 }
    9688 ++(*nchgcoefs);
    9689
    9690 assert(consdata->vars == vars);
    9691 assert(consdata->nvars == nvars);
    9692 assert(consdata->weights == weights);
    9693
    9694 CONTINUE:
    9695 /* now constraint can be normalized, dividing it by the gcd */
    9696 for( v = nvars - 1; v >= 0; --v )
    9697 {
    9698 consdataChgWeight(consdata, v, weights[v]/gcd);
    9699 }
    9700 (*nchgcoefs) += nvars;
    9701
    9702 consdata->capacity /= gcd;
    9703 ++(*nchgsides);
    9704
    9706
    9707 SCIPdebugMsg(scip, "we did %d coefficient changes and %d side changes on constraint %s when applying one round of the gcd algorithm\n", *nchgcoefs - oldnchgcoefs, *nchgsides - oldnchgsides, SCIPconsGetName(cons));
    9708 }
    9709 while( nvars >= 2 );
    9710
    9711 return SCIP_OKAY;
    9712}
    9713
    9714
    9715/** inserts an element into the list of binary zero implications */
    9716static
    9718 SCIP* scip, /**< SCIP data structure */
    9719 int** liftcands, /**< array of the lifting candidates */
    9720 int* nliftcands, /**< number of lifting candidates */
    9721 int** firstidxs, /**< array of first zeroitems indices */
    9722 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
    9723 int** zeroitems, /**< pointer to zero items array */
    9724 int** nextidxs, /**< pointer to array of next zeroitems indeces */
    9725 int* zeroitemssize, /**< pointer to size of zero items array */
    9726 int* nzeroitems, /**< pointer to length of zero items array */
    9727 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
    9728 SCIP_Bool value, /**< value v of variable y in implication */
    9729 int knapsackidx, /**< index of variable x in knapsack */
    9730 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
    9731 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
    9732 )
    9733{
    9734 int nzeros;
    9735
    9736 assert(liftcands != NULL);
    9737 assert(liftcands[value] != NULL);
    9738 assert(nliftcands != NULL);
    9739 assert(firstidxs != NULL);
    9740 assert(firstidxs[value] != NULL);
    9741 assert(zeroweightsums != NULL);
    9742 assert(zeroweightsums[value] != NULL);
    9743 assert(zeroitems != NULL);
    9744 assert(nextidxs != NULL);
    9745 assert(zeroitemssize != NULL);
    9746 assert(nzeroitems != NULL);
    9747 assert(*nzeroitems <= *zeroitemssize);
    9748 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
    9749 assert(memlimitreached != NULL);
    9750
    9751 nzeros = *nzeroitems;
    9752
    9753 /* allocate enough memory */
    9754 if( nzeros == *zeroitemssize )
    9755 {
    9756 /* we explicitly construct the complete implication graph where the knapsack variables are involved;
    9757 * this can be too huge - abort on memory limit
    9758 */
    9759 if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
    9760 {
    9761 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
    9762 *zeroitemssize);
    9763 *memlimitreached = TRUE;
    9764 return SCIP_OKAY;
    9765 }
    9766 *zeroitemssize *= 2;
    9767 *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
    9768 SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
    9769 SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
    9770 }
    9771 assert(nzeros < *zeroitemssize);
    9772
    9773 if( *memlimitreached )
    9774 *memlimitreached = FALSE;
    9775
    9776 /* insert element */
    9777 (*zeroitems)[nzeros] = knapsackidx;
    9778 (*nextidxs)[nzeros] = firstidxs[value][probindex];
    9779 if( firstidxs[value][probindex] == 0 )
    9780 {
    9781 liftcands[value][nliftcands[value]] = probindex;
    9782 ++nliftcands[value];
    9783 }
    9784 firstidxs[value][probindex] = nzeros;
    9785 ++(*nzeroitems);
    9786 zeroweightsums[value][probindex] += knapsackweight;
    9787
    9788 return SCIP_OKAY;
    9789}
    9790
    9791#define MAX_CLIQUELENGTH 50
    9792/** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
    9793 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
    9794 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
    9795 * if cliqueweightsum(xi == v) < capacity:
    9796 * - fixing variable xi to v would make the knapsack constraint redundant
    9797 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
    9798 * redundancy effect:
    9799 * wi' := capacity - cliqueweightsum(xi == v)
    9800 * this rule can also be applied to binary variables not in the knapsack!
    9801 */
    9802static
    9804 SCIP* scip, /**< SCIP data structure */
    9805 SCIP_CONS* cons, /**< knapsack constraint */
    9806 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    9807 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
    9808 )
    9809{
    9810 SCIP_CONSDATA* consdata;
    9811 SCIP_VAR** binvars;
    9812 int nbinvars;
    9813 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
    9814 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
    9815 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
    9816 int* zeroitems; /* item number in knapsack that is implied to zero */
    9817 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
    9818 int zeroitemssize;
    9819 int nzeroitems;
    9820 SCIP_Bool* zeroiteminserted[2];
    9821 SCIP_Bool memlimitreached;
    9822 int nliftcands[2];
    9823 SCIP_Bool* cliqueused;
    9824 SCIP_Bool* itemremoved;
    9825 SCIP_Longint maxcliqueweightsum;
    9826 SCIP_VAR** addvars;
    9827 SCIP_Longint* addweights;
    9828 SCIP_Longint addweightsum;
    9829 int nvars;
    9830 int cliquenum;
    9831 int naddvars;
    9832 int val;
    9833 int i;
    9834
    9835 int* tmpindices;
    9836 SCIP_Bool* tmpboolindices;
    9837 int* tmpindices2;
    9838 SCIP_Bool* tmpboolindices2;
    9839 int* tmpindices3;
    9840 SCIP_Bool* tmpboolindices3;
    9841 int tmp;
    9842 int tmp2;
    9843 int tmp3;
    9844 SCIP_CONSHDLR* conshdlr;
    9845 SCIP_CONSHDLRDATA* conshdlrdata;
    9846
    9847 assert(nchgcoefs != NULL);
    9848 assert(!SCIPconsIsModifiable(cons));
    9849
    9850 consdata = SCIPconsGetData(cons);
    9851 assert(consdata != NULL);
    9852 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
    9853 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
    9854 assert(consdata->nvars > 0);
    9855 assert(consdata->merged);
    9856
    9857 nvars = consdata->nvars;
    9858
    9859 /* check if the knapsack has too many items/cliques for applying this costly method */
    9860 if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
    9861 return SCIP_OKAY;
    9862
    9863 /* sort items, s.t. the heaviest one is in the first position */
    9864 sortItems(consdata);
    9865
    9866 if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
    9867 return SCIP_OKAY;
    9868
    9869 /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
    9870 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    9871 assert(nbinvars > 0);
    9872 binvars = SCIPgetVars(scip);
    9873
    9874 /* get conshdlrdata to use cleared memory */
    9875 conshdlr = SCIPconsGetHdlr(cons);
    9876 assert(conshdlr != NULL);
    9877 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9878 assert(conshdlrdata != NULL);
    9879
    9880 /* allocate temporary memory for the list of implied to zero variables */
    9881 zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
    9882 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
    9883 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
    9884
    9885 assert(conshdlrdata->ints1size > 0);
    9886 assert(conshdlrdata->ints2size > 0);
    9887 assert(conshdlrdata->longints1size > 0);
    9888 assert(conshdlrdata->longints2size > 0);
    9889
    9890 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
    9891 * than binary + integer variables existed at the presolving initialization method, but for example if you would
    9892 * transform all integers into their binary representation then it maybe happens
    9893 */
    9894 if( conshdlrdata->ints1size < nbinvars )
    9895 {
    9896 int oldsize = conshdlrdata->ints1size;
    9897
    9898 conshdlrdata->ints1size = nbinvars;
    9899 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
    9900 BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
    9901 }
    9902 if( conshdlrdata->ints2size < nbinvars )
    9903 {
    9904 int oldsize = conshdlrdata->ints2size;
    9905
    9906 conshdlrdata->ints2size = nbinvars;
    9907 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
    9908 BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
    9909 }
    9910 if( conshdlrdata->longints1size < nbinvars )
    9911 {
    9912 int oldsize = conshdlrdata->longints1size;
    9913
    9914 conshdlrdata->longints1size = nbinvars;
    9915 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
    9916 BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
    9917 }
    9918 if( conshdlrdata->longints2size < nbinvars )
    9919 {
    9920 int oldsize = conshdlrdata->longints2size;
    9921
    9922 conshdlrdata->longints2size = nbinvars;
    9923 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
    9924 BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
    9925 }
    9926
    9927 firstidxs[0] = conshdlrdata->ints1;
    9928 firstidxs[1] = conshdlrdata->ints2;
    9929 zeroweightsums[0] = conshdlrdata->longints1;
    9930 zeroweightsums[1] = conshdlrdata->longints2;
    9931
    9932 /* check for cleared arrays, all entries are zero */
    9933#ifndef NDEBUG
    9934 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
    9935 {
    9936 assert(firstidxs[0][tmp] == 0);
    9937 assert(firstidxs[1][tmp] == 0);
    9938 assert(zeroweightsums[0][tmp] == 0);
    9939 assert(zeroweightsums[1][tmp] == 0);
    9940 }
    9941#endif
    9942
    9943 SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
    9944 SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
    9945
    9946 zeroitems[0] = -1; /* dummy element */
    9947 nextidxs[0] = -1;
    9948 nzeroitems = 1;
    9949 nliftcands[0] = 0;
    9950 nliftcands[1] = 0;
    9951
    9952 assert(conshdlrdata->bools1size > 0);
    9953 assert(conshdlrdata->bools2size > 0);
    9954
    9955 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
    9956 * than binary + integer variables existed at the presolving initialization method, but for example if you would
    9957 * transform all integers into their binary representation then it maybe happens
    9958 */
    9959 if( conshdlrdata->bools1size < nbinvars )
    9960 {
    9961 int oldsize = conshdlrdata->bools1size;
    9962
    9963 conshdlrdata->bools1size = nbinvars;
    9964 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
    9965 BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
    9966 }
    9967 if( conshdlrdata->bools2size < nbinvars )
    9968 {
    9969 int oldsize = conshdlrdata->bools2size;
    9970
    9971 conshdlrdata->bools2size = nbinvars;
    9972 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
    9973 BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
    9974 }
    9975
    9976 zeroiteminserted[0] = conshdlrdata->bools1;
    9977 zeroiteminserted[1] = conshdlrdata->bools2;
    9978
    9979 /* check for cleared arrays, all entries are zero */
    9980#ifndef NDEBUG
    9981 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
    9982 {
    9983 assert(zeroiteminserted[0][tmp] == 0);
    9984 assert(zeroiteminserted[1][tmp] == 0);
    9985 }
    9986#endif
    9987
    9988 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
    9989 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
    9990 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
    9991 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
    9992 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
    9993 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
    9994
    9995 tmp2 = 0;
    9996 tmp3 = 0;
    9997
    9998 memlimitreached = FALSE;
    9999 for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
    10000 {
    10001 SCIP_CLIQUE** cliques;
    10002 SCIP_VAR* var;
    10003 SCIP_Longint weight;
    10004 SCIP_Bool value;
    10005 int varprobindex;
    10006 int ncliques;
    10007 int j;
    10008
    10009 tmp = 0;
    10010
    10011 /* get corresponding active problem variable */
    10012 var = consdata->vars[i];
    10013 weight = consdata->weights[i];
    10014 value = TRUE;
    10015 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
    10016 varprobindex = SCIPvarGetProbindex(var);
    10017 assert(0 <= varprobindex && varprobindex < nbinvars);
    10018
    10019 /* update the zeroweightsum */
    10020 zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
    10021 tmpboolindices3[tmp3] = !value;
    10022 tmpindices3[tmp3] = varprobindex;
    10023 ++tmp3;
    10024
    10025 /* initialize the arrays of inserted zero items */
    10026 /* first add the implications (~x == 1 -> x == 0) */
    10027 {
    10028 SCIP_Bool implvalue;
    10029 int probindex;
    10030
    10031 probindex = SCIPvarGetProbindex(var);
    10032 assert(0 <= probindex && probindex < nbinvars);
    10033
    10034 implvalue = !value;
    10035
    10036 /* insert the item into the list of the implied variable/value */
    10037 assert( !zeroiteminserted[implvalue][probindex] );
    10038
    10039 if( firstidxs[implvalue][probindex] == 0 )
    10040 {
    10041 tmpboolindices2[tmp2] = implvalue;
    10042 tmpindices2[tmp2] = probindex;
    10043 ++tmp2;
    10044 }
    10045 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
    10046 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
    10047 &memlimitreached) );
    10048 zeroiteminserted[implvalue][probindex] = TRUE;
    10049 tmpboolindices[tmp] = implvalue;
    10050 tmpindices[tmp] = probindex;
    10051 ++tmp;
    10052 }
    10053
    10054 /* get the cliques where the knapsack item is member of with value 1 */
    10055 ncliques = SCIPvarGetNCliques(var, value);
    10056 cliques = SCIPvarGetCliques(var, value);
    10057 for( j = 0; j < ncliques && !memlimitreached; ++j )
    10058 {
    10059 SCIP_VAR** cliquevars;
    10060 SCIP_Bool* cliquevalues;
    10061 int ncliquevars;
    10062 int k;
    10063
    10064 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
    10065
    10066 /* discard big cliques */
    10067 if( ncliquevars > MAX_CLIQUELENGTH )
    10068 continue;
    10069
    10070 cliquevars = SCIPcliqueGetVars(cliques[j]);
    10071 cliquevalues = SCIPcliqueGetValues(cliques[j]);
    10072
    10073 for( k = ncliquevars - 1; k >= 0; --k )
    10074 {
    10075 SCIP_Bool implvalue;
    10076 int probindex;
    10077
    10078 if( var == cliquevars[k] )
    10079 continue;
    10080
    10081 probindex = SCIPvarGetProbindex(cliquevars[k]);
    10082 if( probindex == -1 )
    10083 continue;
    10084
    10085 assert(0 <= probindex && probindex < nbinvars);
    10086 implvalue = cliquevalues[k];
    10087
    10088 /* insert the item into the list of the clique variable/value */
    10089 if( !zeroiteminserted[implvalue][probindex] )
    10090 {
    10091 if( firstidxs[implvalue][probindex] == 0 )
    10092 {
    10093 tmpboolindices2[tmp2] = implvalue;
    10094 tmpindices2[tmp2] = probindex;
    10095 ++tmp2;
    10096 }
    10097
    10098 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
    10099 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
    10100 &memlimitreached) );
    10101 zeroiteminserted[implvalue][probindex] = TRUE;
    10102 tmpboolindices[tmp] = implvalue;
    10103 tmpindices[tmp] = probindex;
    10104 ++tmp;
    10105
    10106 if( memlimitreached )
    10107 break;
    10108 }
    10109 }
    10110 }
    10111 /* clear zeroiteminserted */
    10112 for( --tmp; tmp >= 0; --tmp)
    10113 zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
    10114 }
    10115 SCIPfreeBufferArray(scip, &tmpboolindices);
    10116
    10117 /* calculate the clique partition and the maximal sum of weights using the clique information */
    10118 assert(consdata->sorted);
    10119 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
    10120
    10121 assert(conshdlrdata->bools3size > 0);
    10122
    10123 /* next if condition should normally not be true, because it means that presolving has created more binary variables
    10124 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
    10125 * method, but for example if you would transform all integers into their binary representation then it maybe happens
    10126 */
    10127 if( conshdlrdata->bools3size < consdata->nvars )
    10128 {
    10129 int oldsize = conshdlrdata->bools3size;
    10130
    10131 conshdlrdata->bools3size = consdata->nvars;;
    10132 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
    10133 BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
    10134 }
    10135
    10136 cliqueused = conshdlrdata->bools3;
    10137
    10138 /* check for cleared array, all entries are zero */
    10139#ifndef NDEBUG
    10140 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
    10141 assert(cliqueused[tmp] == 0);
    10142#endif
    10143
    10144 maxcliqueweightsum = 0;
    10145 tmp = 0;
    10146
    10147 /* calculates maximal weight of cliques */
    10148 for( i = 0; i < consdata->nvars; ++i )
    10149 {
    10150 cliquenum = consdata->cliquepartition[i];
    10151 assert(0 <= cliquenum && cliquenum < consdata->nvars);
    10152
    10153 if( !cliqueused[cliquenum] )
    10154 {
    10155 maxcliqueweightsum += consdata->weights[i];
    10156 cliqueused[cliquenum] = TRUE;
    10157 tmpindices[tmp] = cliquenum;
    10158 ++tmp;
    10159 }
    10160 }
    10161 /* clear cliqueused */
    10162 for( --tmp; tmp >= 0; --tmp)
    10163 cliqueused[tmp] = FALSE;
    10164
    10165 assert(conshdlrdata->bools4size > 0);
    10166
    10167 /* next if condition should normally not be true, because it means that presolving has created more binary variables
    10168 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
    10169 * method, but for example if you would transform all integers into their binary representation then it maybe happens
    10170 */
    10171 if( conshdlrdata->bools4size < consdata->nvars )
    10172 {
    10173 int oldsize = conshdlrdata->bools4size;
    10174
    10175 conshdlrdata->bools4size = consdata->nvars;
    10176 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
    10177 BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
    10178 }
    10179
    10180 itemremoved = conshdlrdata->bools4;
    10181
    10182 /* check for cleared array, all entries are zero */
    10183#ifndef NDEBUG
    10184 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
    10185 assert(itemremoved[tmp] == 0);
    10186#endif
    10187
    10188 /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
    10189 * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
    10190 * included in subsequent cliqueweightsum calculations)
    10191 */
    10192 SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
    10193 SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
    10194 naddvars = 0;
    10195 addweightsum = 0;
    10196 for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
    10197 {
    10198 for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
    10199 {
    10200 SCIP_Longint cliqueweightsum;
    10201 int probindex;
    10202 int idx;
    10203 int j;
    10204
    10205 tmp = 0;
    10206
    10207 probindex = liftcands[val][i];
    10208 assert(0 <= probindex && probindex < nbinvars);
    10209
    10210 /* ignore empty zero lists and variables that cannot be lifted anyways */
    10211 if( firstidxs[val][probindex] == 0
    10212 || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
    10213 continue;
    10214
    10215 /* mark the items that are implied to zero by setting the current variable to the current value */
    10216 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
    10217 {
    10218 assert(0 < idx && idx < nzeroitems);
    10219 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
    10220 itemremoved[zeroitems[idx]] = TRUE;
    10221 }
    10222
    10223 /* calculate the residual cliqueweight sum */
    10224 cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
    10225 for( j = 0; j < consdata->nvars; ++j )
    10226 {
    10227 cliquenum = consdata->cliquepartition[j];
    10228 assert(0 <= cliquenum && cliquenum < consdata->nvars);
    10229 if( !itemremoved[j] )
    10230 {
    10231 if( !cliqueused[cliquenum] )
    10232 {
    10233 cliqueweightsum += consdata->weights[j];
    10234 cliqueused[cliquenum] = TRUE;
    10235 tmpindices[tmp] = cliquenum;
    10236 ++tmp;
    10237 }
    10238
    10239 if( cliqueweightsum >= consdata->capacity )
    10240 break;
    10241 }
    10242 }
    10243
    10244 /* check if the weight of the variable/value can be increased */
    10245 if( cliqueweightsum < consdata->capacity )
    10246 {
    10247 SCIP_VAR* var;
    10248 SCIP_Longint weight;
    10249
    10250 /* insert the variable (with value TRUE) in the list of additional items */
    10251 assert(naddvars < 2*nbinvars);
    10252 var = binvars[probindex];
    10253 if( val == FALSE )
    10254 {
    10255 SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
    10256 }
    10257 weight = consdata->capacity - cliqueweightsum;
    10258 addvars[naddvars] = var;
    10259 addweights[naddvars] = weight;
    10260 addweightsum += weight;
    10261 naddvars++;
    10262
    10263 SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
    10264 SCIPconsGetName(cons), weight, SCIPvarGetName(var));
    10265 }
    10266
    10267 /* clear itemremoved */
    10268 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
    10269 {
    10270 assert(0 < idx && idx < nzeroitems);
    10271 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
    10272 itemremoved[zeroitems[idx]] = FALSE;
    10273 }
    10274 /* clear cliqueused */
    10275 for( --tmp; tmp >= 0; --tmp)
    10276 cliqueused[tmpindices[tmp]] = FALSE;
    10277 }
    10278 }
    10279
    10280 /* clear part of zeroweightsums */
    10281 for( --tmp3; tmp3 >= 0; --tmp3)
    10282 zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
    10283
    10284 /* clear rest of zeroweightsums and firstidxs */
    10285 for( --tmp2; tmp2 >= 0; --tmp2)
    10286 {
    10287 zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
    10288 firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
    10289 }
    10290
    10291 /* add all additional item weights */
    10292 for( i = 0; i < naddvars; ++i )
    10293 {
    10294 SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
    10295 }
    10296 *nchgcoefs += naddvars;
    10297
    10298 if( naddvars > 0 )
    10299 {
    10300 /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
    10301 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    10302 }
    10303
    10304 /* free temporary memory */
    10305 SCIPfreeBufferArray(scip, &addweights);
    10306 SCIPfreeBufferArray(scip, &addvars);
    10307 SCIPfreeBufferArray(scip, &tmpindices);
    10308 SCIPfreeBufferArray(scip, &tmpindices2);
    10309 SCIPfreeBufferArray(scip, &tmpindices3);
    10310 SCIPfreeBufferArray(scip, &tmpboolindices2);
    10311 SCIPfreeBufferArray(scip, &tmpboolindices3);
    10312 SCIPfreeBufferArray(scip, &nextidxs);
    10313 SCIPfreeBufferArray(scip, &zeroitems);
    10314 SCIPfreeBufferArray(scip, &liftcands[1]);
    10315 SCIPfreeBufferArray(scip, &liftcands[0]);
    10316
    10317 return SCIP_OKAY;
    10318}
    10319
    10320/** tightens item weights and capacity in presolving:
    10321 * given a knapsack sum(wi*xi) <= capacity
    10322 * (1) let weightsum := sum(wi)
    10323 * if weightsum - wi < capacity:
    10324 * - not using item i would make the knapsack constraint redundant
    10325 * - wi and capacity can be changed to have the same redundancy effect and the same results for
    10326 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
    10327 * - change coefficients:
    10328 * wi' := weightsum - capacity
    10329 * capacity' := capacity - (wi - wi')
    10330 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
    10331 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
    10332 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
    10333 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
    10334 * can be multiple times the same weight, this can be improved
    10335 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
    10336 * weight, to capacity - lastmininmalweightsum, e.g. :
    10337 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
    10338 * -> minimal weightsums: 5, 5, 10, 10
    10339 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
    10340 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
    10341 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
    10342 * (3) let W(C) be the maximal weight of clique C,
    10343 * cliqueweightsum := sum(W(C))
    10344 * if cliqueweightsum - W(C) < capacity:
    10345 * - not using any item of C would make the knapsack constraint redundant
    10346 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
    10347 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
    10348 * - change coefficients:
    10349 * delta := capacity - (cliqueweightsum - W(C))
    10350 * wi' := max(wi - delta, 0)
    10351 * capacity' := capacity - delta
    10352 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
    10353 * introduce infeasible solutions.
    10354 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
    10355 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
    10356 * if cliqueweightsum(xi == v) < capacity:
    10357 * - fixing variable xi to v would make the knapsack constraint redundant
    10358 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
    10359 * redundancy effect:
    10360 * wi' := capacity - cliqueweightsum(xi == v)
    10361 * This rule can also be applied to binary variables not in the knapsack!
    10362 * (5) if min{w} + wi > capacity:
    10363 * - using item i would force to fix other items to zero
    10364 * - wi can be increased to the capacity
    10365 */
    10366static
    10368 SCIP* scip, /**< SCIP data structure */
    10369 SCIP_CONS* cons, /**< knapsack constraint */
    10370 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
    10371 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    10372 int* nchgsides, /**< pointer to count number of side changes */
    10373 int* naddconss, /**< pointer to count number of added constraints */
    10374 int* ndelconss, /**< pointer to count number of deleted constraints */
    10375 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
    10376 )
    10377{
    10378 SCIP_CONSHDLRDATA* conshdlrdata;
    10379 SCIP_CONSDATA* consdata;
    10380 SCIP_Longint* weights;
    10381 SCIP_Longint sumcoef;
    10382 SCIP_Longint capacity;
    10383 SCIP_Longint newweight;
    10384 SCIP_Longint maxweight;
    10385 SCIP_Longint minweight;
    10386 SCIP_Bool sumcoefcase = FALSE;
    10387 int startpos;
    10388 int backpos;
    10389 int nvars;
    10390 int pos;
    10391 int k;
    10392 int i;
    10393
    10394 assert(nchgcoefs != NULL);
    10395 assert(nchgsides != NULL);
    10396 assert(!SCIPconsIsModifiable(cons));
    10397
    10398 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    10399 assert(conshdlrdata != NULL);
    10400
    10401 consdata = SCIPconsGetData(cons);
    10402 assert(consdata != NULL);
    10403 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
    10404 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
    10405 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
    10406 assert(consdata->nvars > 0);
    10407
    10408 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    10409 if( *cutoff )
    10410 return SCIP_OKAY;
    10411
    10412 /* apply rule (1) */
    10413 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    10414 {
    10415 do
    10416 {
    10417 assert(consdata->merged);
    10418
    10419 /* sort items, s.t. the heaviest one is in the first position */
    10420 sortItems(consdata);
    10421
    10422 for( i = 0; i < consdata->nvars; ++i )
    10423 {
    10424 SCIP_Longint weight;
    10425
    10426 weight = consdata->weights[i];
    10427 if( consdata->weightsum - weight < consdata->capacity )
    10428 {
    10429 newweight = consdata->weightsum - consdata->capacity;
    10430 consdataChgWeight(consdata, i, newweight);
    10431 consdata->capacity -= (weight - newweight);
    10432 (*nchgcoefs)++;
    10433 (*nchgsides)++;
    10434 assert(!consdata->sorted);
    10435 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT ", capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10436 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
    10437 consdata->capacity + (weight-newweight), consdata->capacity);
    10438 }
    10439 else
    10440 break;
    10441 }
    10442 }
    10443 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
    10444 }
    10445
    10446 /* check for redundancy */
    10447 if( consdata->weightsum <= consdata->capacity )
    10448 return SCIP_OKAY;
    10449
    10450 pos = 0;
    10451 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
    10452 ++pos;
    10453
    10454 sumcoef = 0;
    10455 weights = consdata->weights;
    10456 nvars = consdata->nvars;
    10457 capacity = consdata->capacity;
    10458
    10459 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
    10460 pos < nvars && weights[pos] + weights[pos + 1] > capacity )
    10461 {
    10462 /* further reductions using the next possible coefficient sum
    10463 *
    10464 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
    10465 */
    10466 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
    10467 for( k = 0; k < 4; ++k )
    10468 {
    10469 newweight = capacity - sumcoef;
    10470
    10471 /* determine next minimal coefficient sum */
    10472 switch( k )
    10473 {
    10474 case 0:
    10475 sumcoef = weights[nvars - 1];
    10476 backpos = nvars - 1;
    10477 break;
    10478 case 1:
    10479 sumcoef = weights[nvars - 2];
    10480 backpos = nvars - 2;
    10481 break;
    10482 case 2:
    10483 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
    10484 {
    10485 sumcoefcase = TRUE;
    10486 sumcoef = weights[nvars - 3];
    10487 backpos = nvars - 3;
    10488 }
    10489 else
    10490 {
    10491 sumcoefcase = FALSE;
    10492 sumcoef = weights[nvars - 1] + weights[nvars - 2];
    10493 backpos = nvars - 2;
    10494 }
    10495 break;
    10496 default:
    10497 assert(k == 3);
    10498 if( sumcoefcase )
    10499 {
    10500 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
    10501 {
    10502 sumcoef = weights[nvars - 4];
    10503 backpos = nvars - 4;
    10504 }
    10505 else
    10506 {
    10507 sumcoef = weights[nvars - 1] + weights[nvars - 2];
    10508 backpos = nvars - 2;
    10509 }
    10510 }
    10511 else
    10512 {
    10513 sumcoef = weights[nvars - 3];
    10514 backpos = nvars - 3;
    10515 }
    10516 break;
    10517 }
    10518
    10519 if( backpos <= pos )
    10520 break;
    10521
    10522 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
    10523 maxweight = weights[pos];
    10524 startpos = pos;
    10525 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
    10526 {
    10527 assert(newweight > weights[pos]);
    10528
    10529 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10530 SCIPconsGetName(cons), maxweight, newweight);
    10531
    10532 consdataChgWeight(consdata, pos, newweight);
    10533
    10534 ++pos;
    10535 assert(pos < nvars);
    10536
    10537 maxweight = weights[pos];
    10538
    10539 if( backpos <= pos )
    10540 break;
    10541 }
    10542 (*nchgcoefs) += (pos - startpos);
    10543
    10544 /* skip unchangable weights */
    10545 while( pos < nvars && weights[pos] + sumcoef == capacity )
    10546 ++pos;
    10547
    10548 /* check special case were there is only one weight left to tighten
    10549 *
    10550 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
    10551 *
    10552 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
    10553 *
    10554 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
    10555 */
    10556 if( pos + 1 == backpos && weights[pos] > sumcoef &&
    10557 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
    10558 {
    10559 newweight = capacity - sumcoef;
    10560 assert(newweight > weights[pos]);
    10561
    10562 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10563 SCIPconsGetName(cons), maxweight, newweight);
    10564
    10565 consdataChgWeight(consdata, pos, newweight);
    10566
    10567 break;
    10568 }
    10569
    10570 if( backpos <= pos )
    10571 break;
    10572 }
    10573 }
    10574
    10575 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
    10576 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    10577 {
    10578 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0
    10579 && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 && pos > 0
    10580 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity
    10581 && consdata->weights[pos - 1] == consdata->capacity
    10582 && ( pos == consdata->nvars || consdata->weights[pos] == 1 ) )
    10583 {
    10584 SCIP_VAR** clqvars;
    10585 SCIP_CONS* cliquecons;
    10586 char name[SCIP_MAXSTRLEN];
    10587 int* clqpart;
    10588 int nclqvars;
    10589 int nclq;
    10590 int len;
    10591 int c;
    10592 int w;
    10593
    10594 assert(!SCIPconsIsDeleted(cons));
    10595
    10596 if( pos == consdata->nvars )
    10597 {
    10598 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
    10599
    10600 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
    10604 SCIPconsIsStickingAtNode(cons)) );
    10605
    10606 /* add the upgraded constraint to the problem */
    10607 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    10608 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    10609 ++(*naddconss);
    10610
    10611 /* delete old constraint */
    10612 SCIP_CALL( SCIPdelCons(scip, cons) );
    10613 ++(*ndelconss);
    10614
    10615 return SCIP_OKAY;
    10616 }
    10617
    10618 len = consdata->nvars - pos;
    10619
    10620 /* allocate temporary memory */
    10621 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
    10622
    10623 /* calculate clique partition */
    10624 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
    10625 assert(nclq <= len);
    10626
    10627#ifndef NDEBUG
    10628 /* clique numbers must be at least as high as the index */
    10629 for( w = 0; w < nclq; ++w )
    10630 assert(clqpart[w] <= w);
    10631#endif
    10632
    10633 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
    10634
    10635 /* allocate temporary memory */
    10636 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
    10637
    10638 /* copy corresponding variables with big coefficients */
    10639 for( w = pos - 1; w >= 0; --w )
    10640 clqvars[w] = consdata->vars[w];
    10641
    10642 /* create for each clique a set-packing constraint */
    10643 for( c = 0; c < nclq; ++c )
    10644 {
    10645 nclqvars = pos;
    10646
    10647 for( w = c; w < len; ++w )
    10648 {
    10649 if( clqpart[w] == c )
    10650 {
    10651 assert(nclqvars < pos + len - nclq + 1);
    10652 clqvars[nclqvars] = consdata->vars[w + pos];
    10653 ++nclqvars;
    10654 }
    10655 }
    10656
    10657 assert(nclqvars > 1);
    10658
    10659 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
    10660 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
    10664 SCIPconsIsStickingAtNode(cons)) );
    10665
    10666 /* add the special constraint to the problem */
    10667 SCIPdebugMsg(scip, " -> adding clique constraint: ");
    10668 SCIPdebugPrintCons(scip, cliquecons, NULL);
    10669 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    10670 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    10671 ++(*naddconss);
    10672 }
    10673
    10674 /* delete old constraint */
    10675 SCIP_CALL( SCIPdelCons(scip, cons) );
    10676 ++(*ndelconss);
    10677
    10678 SCIPfreeBufferArray(scip, &clqvars);
    10679 SCIPfreeBufferArray(scip, &clqpart);
    10680
    10681 return SCIP_OKAY;
    10682 }
    10683 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
    10684 {
    10685 SCIP_Longint* maxcliqueweights;
    10686 SCIP_Longint* newweightvals;
    10687 int* newweightidxs;
    10688 SCIP_Longint cliqueweightsum;
    10689
    10690 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
    10691 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
    10692 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
    10693
    10694 /* repeat as long as changes have been applied */
    10695 do
    10696 {
    10697 int ncliques;
    10698 int cliquenum;
    10699 SCIP_Bool zeroweights;
    10700
    10701 assert(consdata->merged);
    10702
    10703 /* sort items, s.t. the heaviest one is in the first position */
    10704 sortItems(consdata);
    10705
    10706 /* calculate a clique partition */
    10707 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
    10708
    10709 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
    10710 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
    10711 break;
    10712
    10713 /* calculate the maximal weight of the cliques and store the clique type */
    10714 cliqueweightsum = 0;
    10715 ncliques = 0;
    10716
    10717 for( i = 0; i < consdata->nvars; ++i )
    10718 {
    10719 SCIP_Longint weight;
    10720
    10721 cliquenum = consdata->cliquepartition[i];
    10722 assert(0 <= cliquenum && cliquenum <= ncliques);
    10723
    10724 weight = consdata->weights[i];
    10725 assert(weight > 0);
    10726
    10727 if( cliquenum == ncliques )
    10728 {
    10729 maxcliqueweights[ncliques] = weight;
    10730 cliqueweightsum += weight;
    10731 ++ncliques;
    10732 }
    10733
    10734 assert(maxcliqueweights[cliquenum] >= weight);
    10735 }
    10736
    10737 /* apply rule on every clique */
    10738 zeroweights = FALSE;
    10739 for( i = 0; i < ncliques; ++i )
    10740 {
    10741 SCIP_Longint delta;
    10742
    10743 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
    10744 if( delta > 0 )
    10745 {
    10746 SCIP_Longint newcapacity;
    10747#ifndef NDEBUG
    10748 SCIP_Longint newmincliqueweight;
    10749#endif
    10750 SCIP_Longint newminweightsuminclique;
    10751 SCIP_Bool forceclique;
    10752 int nnewweights;
    10753 int j;
    10754
    10755 SCIPdebugMsg(scip, "knapsack constraint <%s>: weights of clique %d (maxweight: %" SCIP_LONGINT_FORMAT ") can be tightened: cliqueweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT " -> delta: %" SCIP_LONGINT_FORMAT "\n",
    10756 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
    10757 newcapacity = consdata->capacity - delta;
    10758 forceclique = FALSE;
    10759 nnewweights = 0;
    10760#ifndef NDEBUG
    10761 newmincliqueweight = newcapacity + 1;
    10762 for( j = 0; j < i; ++j )
    10763 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
    10764#endif
    10765 for( j = i; j < consdata->nvars; ++j )
    10766 {
    10767 if( consdata->cliquepartition[j] == i )
    10768 {
    10769 newweight = consdata->weights[j] - delta;
    10770 newweight = MAX(newweight, 0);
    10771
    10772 /* cache the new weight */
    10773 assert(nnewweights < consdata->nvars);
    10774 newweightvals[nnewweights] = newweight;
    10775 newweightidxs[nnewweights] = j;
    10776 nnewweights++;
    10777
    10778#ifndef NDEBUG
    10779 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
    10780 newmincliqueweight = newweight;
    10781#endif
    10782 }
    10783 }
    10784
    10785 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
    10786 if( nnewweights > 1 )
    10787 {
    10788#ifndef NDEBUG
    10789 j = newweightidxs[nnewweights - 2];
    10790 assert(0 <= j && j < consdata->nvars);
    10791 assert(consdata->cliquepartition[j] == i);
    10792 j = newweightidxs[nnewweights - 1];
    10793 assert(0 <= j && j < consdata->nvars);
    10794 assert(consdata->cliquepartition[j] == i);
    10795#endif
    10796
    10797 newminweightsuminclique = newweightvals[nnewweights - 2];
    10798 newminweightsuminclique += newweightvals[nnewweights - 1];
    10799
    10800 /* check if these new two minimal weights both fit into the knapsack;
    10801 * if this is true, we have to add a clique constraint in order to enforce the clique
    10802 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
    10803 * reduction might be infeasible, i.e., allows additional solutions)
    10804 */
    10805 if( newminweightsuminclique <= newcapacity )
    10806 forceclique = TRUE;
    10807 }
    10808
    10809 /* check if we really want to apply the change */
    10810 if( conshdlrdata->disaggregation || !forceclique )
    10811 {
    10812 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
    10813 consdata->capacity, newcapacity, forceclique);
    10814 consdata->capacity = newcapacity;
    10815 (*nchgsides)++;
    10816
    10817 for( k = 0; k < nnewweights; ++k )
    10818 {
    10819 j = newweightidxs[k];
    10820 assert(0 <= j && j < consdata->nvars);
    10821 assert(consdata->cliquepartition[j] == i);
    10822
    10823 /* apply the weight change */
    10824 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10825 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
    10826 consdataChgWeight(consdata, j, newweightvals[k]);
    10827 (*nchgcoefs)++;
    10828 assert(!consdata->sorted);
    10829 zeroweights = zeroweights || (newweightvals[k] == 0);
    10830 }
    10831 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
    10832 * we have to make sure, the clique is enforced - the clique might have been constructed partially from
    10833 * this constraint, and by reducing the weights, this clique information is not contained anymore in the
    10834 * knapsack constraint
    10835 */
    10836 if( forceclique )
    10837 {
    10838 SCIP_CONS* cliquecons;
    10839 char name[SCIP_MAXSTRLEN];
    10840 SCIP_VAR** cliquevars;
    10841
    10842 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
    10843 for( k = 0; k < nnewweights; ++k )
    10844 cliquevars[k] = consdata->vars[newweightidxs[k]];
    10845
    10846 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
    10847 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
    10851 SCIPconsIsStickingAtNode(cons)) );
    10852
    10853 /* add the special constraint to the problem */
    10854 SCIPdebugMsg(scip, " -> adding clique constraint: ");
    10855 SCIPdebugPrintCons(scip, cliquecons, NULL);
    10856 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    10857 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    10858 ++(*naddconss);
    10859
    10860 /* free clique array */
    10861 SCIPfreeBufferArray(scip, &cliquevars);
    10862 }
    10863 }
    10864 }
    10865 }
    10866 if( zeroweights )
    10867 {
    10869 }
    10870 }
    10871 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
    10872
    10873 /* free temporary memory */
    10874 SCIPfreeBufferArray(scip, &newweightidxs);
    10875 SCIPfreeBufferArray(scip, &newweightvals);
    10876 SCIPfreeBufferArray(scip, &maxcliqueweights);
    10877
    10878 /* check for redundancy */
    10879 if( consdata->weightsum <= consdata->capacity )
    10880 return SCIP_OKAY;
    10881 }
    10882 }
    10883
    10884 /* apply rule (3) */
    10885 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    10886 {
    10887 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
    10888 }
    10889
    10890 /* check for redundancy */
    10891 if( consdata->weightsum <= consdata->capacity )
    10892 return SCIP_OKAY;
    10893
    10894 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    10895 {
    10896 /* apply rule (4) (all but smallest weight) */
    10897 assert(consdata->merged);
    10898 sortItems(consdata);
    10899 minweight = consdata->weights[consdata->nvars-1];
    10900 for( i = 0; i < consdata->nvars-1; ++i )
    10901 {
    10902 SCIP_Longint weight;
    10903
    10904 weight = consdata->weights[i];
    10905 assert(weight >= minweight);
    10906 if( minweight + weight > consdata->capacity )
    10907 {
    10908 if( weight < consdata->capacity )
    10909 {
    10910 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10911 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
    10912 assert(consdata->sorted);
    10913 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
    10914 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
    10915 consdata->sorted = TRUE;
    10916 (*nchgcoefs)++;
    10917 }
    10918 }
    10919 else
    10920 break;
    10921 }
    10922
    10923 /* apply rule (5) (smallest weight) */
    10924 if( consdata->nvars >= 2 )
    10925 {
    10926 SCIP_Longint weight;
    10927
    10928 minweight = consdata->weights[consdata->nvars-2];
    10929 weight = consdata->weights[consdata->nvars-1];
    10930 assert(minweight >= weight);
    10931 if( minweight + weight > consdata->capacity && weight < consdata->capacity )
    10932 {
    10933 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10934 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
    10935 assert(consdata->sorted);
    10936 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
    10937 assert(minweight >= consdata->weights[consdata->nvars-1]);
    10938 consdata->sorted = TRUE;
    10939 (*nchgcoefs)++;
    10940 }
    10941 }
    10942 }
    10943
    10944 return SCIP_OKAY;
    10945}
    10946
    10947
    10948#ifdef SCIP_DEBUG
    10949static
    10950void printClique(
    10951 SCIP_VAR** cliquevars,
    10952 int ncliquevars
    10953 )
    10954{
    10955 int b;
    10956 SCIPdebugMessage("adding new Clique: ");
    10957 for( b = 0; b < ncliquevars; ++b )
    10958 SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
    10959 SCIPdebugPrintf("\n");
    10960}
    10961#endif
    10962
    10963/** adds negated cliques of the knapsack constraint to the global clique table */
    10964static
    10966 SCIP*const scip, /**< SCIP data structure */
    10967 SCIP_CONS*const cons, /**< knapsack constraint */
    10968 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
    10969 int*const nbdchgs /**< pointer to count the number of performed bound changes */
    10970 )
    10971{
    10972 SCIP_CONSDATA* consdata;
    10973 SCIP_CONSHDLRDATA* conshdlrdata;
    10974 SCIP_VAR** poscliquevars;
    10975 SCIP_VAR** cliquevars;
    10976 SCIP_Longint* maxweights;
    10977 SCIP_Longint* gainweights;
    10978 int* gaincliquepartition;
    10979 SCIP_Bool* cliqueused;
    10980 SCIP_Longint minactduetonegcliques;
    10981 SCIP_Longint freecapacity;
    10982 SCIP_Longint lastweight;
    10983 SCIP_Longint beforelastweight;
    10984 int nposcliquevars;
    10985 int ncliquevars;
    10986 int nvars;
    10987 int nnegcliques;
    10988 int lastcliqueused;
    10989 int thisnbdchgs;
    10990 int v;
    10991 int w;
    10992
    10993 assert(scip != NULL);
    10994 assert(cons != NULL);
    10995 assert(cutoff != NULL);
    10996 assert(nbdchgs != NULL);
    10997
    10998 *cutoff = FALSE;
    10999
    11000 consdata = SCIPconsGetData(cons);
    11001 assert(consdata != NULL);
    11002
    11003 nvars = consdata->nvars;
    11004
    11005 /* check whether the cliques have already been added */
    11006 if( consdata->cliquesadded || nvars == 0 )
    11007 return SCIP_OKAY;
    11008
    11009 /* make sure, the items are merged */
    11010 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    11011 if( *cutoff )
    11012 return SCIP_OKAY;
    11013
    11014 /* make sure, items are sorted by non-increasing weight */
    11015 sortItems(consdata);
    11016
    11017 assert(consdata->merged);
    11018
    11019 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    11020 assert(conshdlrdata != NULL);
    11021
    11022 /* calculate a clique partition */
    11023 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
    11024 nnegcliques = consdata->nnegcliques;
    11025
    11026 /* if we have no negated cliques, stop */
    11027 if( nnegcliques == nvars )
    11028 return SCIP_OKAY;
    11029
    11030 /* get temporary memory */
    11031 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
    11032 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
    11033 SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
    11034 SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
    11035 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
    11036 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
    11037
    11038 nnegcliques = 0;
    11039 minactduetonegcliques = 0;
    11040
    11041 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
    11042 for( v = 0; v < nvars; ++v )
    11043 {
    11044 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
    11045 assert(consdata->weights[v] > 0);
    11046
    11047 if( consdata->negcliquepartition[v] == nnegcliques )
    11048 {
    11049 nnegcliques++;
    11050 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
    11051 }
    11052 else
    11053 minactduetonegcliques += consdata->weights[v];
    11054 }
    11055
    11056 nposcliquevars = 0;
    11057
    11058 /* add cliques, using negated cliques information */
    11059 if( minactduetonegcliques > 0 )
    11060 {
    11061 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
    11062 freecapacity = consdata->capacity - minactduetonegcliques;
    11063
    11065 SCIPdebugMsg(scip, "Try to add negated cliques in knapsack constraint handler for constraint %s; capacity = %" SCIP_LONGINT_FORMAT ", minactivity(due to neg. cliques) = %" SCIP_LONGINT_FORMAT ", freecapacity = %" SCIP_LONGINT_FORMAT ".\n",
    11066 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
    11067
    11068 /* calculate possible gain by switching chosen items in negated cliques */
    11069 for( v = 0; v < nvars; ++v )
    11070 {
    11071 if( !cliqueused[consdata->negcliquepartition[v]] )
    11072 {
    11073 cliqueused[consdata->negcliquepartition[v]] = TRUE;
    11074 for( w = v + 1; w < nvars; ++w )
    11075 {
    11076 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
    11077 * weight[w] (which are both in a negated clique) */
    11078 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
    11079 && consdata->weights[v] > consdata->weights[w] )
    11080 {
    11081 poscliquevars[nposcliquevars] = consdata->vars[w];
    11082 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
    11083 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
    11084 ++nposcliquevars;
    11085 }
    11086 }
    11087 }
    11088 }
    11089
    11090 /* try to create negated cliques */
    11091 if( nposcliquevars > 0 )
    11092 {
    11093 /* sort possible gain per substitution of the clique members */
    11094 SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
    11095
    11096 for( v = 0; v < nposcliquevars; ++v )
    11097 {
    11098 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
    11099 ncliquevars = 1;
    11100 lastweight = gainweights[v];
    11101 beforelastweight = -1;
    11102 lastcliqueused = gaincliquepartition[v];
    11103 /* clear cliqueused to get an unused array */
    11104 BMSclearMemoryArray(cliqueused, nnegcliques);
    11105 cliqueused[gaincliquepartition[v]] = TRUE;
    11106
    11107 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
    11108 * in the same negated clique and by taking two of them would exceed the free capacity */
    11109 for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
    11110 {
    11111 beforelastweight = lastweight;
    11112 lastweight = gainweights[w];
    11113 lastcliqueused = gaincliquepartition[w];
    11114 cliqueused[gaincliquepartition[w]] = TRUE;
    11115 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
    11116 ++ncliquevars;
    11117 }
    11118
    11119 if( ncliquevars > 1 )
    11120 {
    11121 SCIPdebug( printClique(cliquevars, ncliquevars) );
    11122 assert(beforelastweight > 0);
    11123 /* add the clique to the clique table */
    11124 /* this really happens, e.g., on enigma.mps from the short test set */
    11125 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
    11126 if( *cutoff )
    11127 goto TERMINATE;
    11128 *nbdchgs += thisnbdchgs;
    11129
    11130 /* reset last used clique to get slightly different cliques */
    11131 cliqueused[lastcliqueused] = FALSE;
    11132
    11133 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
    11134 for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
    11135 {
    11136 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
    11137 SCIPdebug( printClique(cliquevars, ncliquevars) );
    11138 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
    11139 if( *cutoff )
    11140 goto TERMINATE;
    11141 *nbdchgs += thisnbdchgs;
    11142 }
    11143 }
    11144 }
    11145 }
    11146 }
    11147
    11148 TERMINATE:
    11149 /* free temporary memory */
    11150 SCIPfreeBufferArray(scip, &cliqueused);
    11151 SCIPfreeBufferArray(scip, &maxweights);
    11152 SCIPfreeBufferArray(scip, &gaincliquepartition);
    11153 SCIPfreeBufferArray(scip, &gainweights);
    11154 SCIPfreeBufferArray(scip, &cliquevars);
    11155 SCIPfreeBufferArray(scip, &poscliquevars);
    11156
    11157 return SCIP_OKAY;
    11158}
    11159
    11160/** greedy clique detection by considering weights and capacity
    11161 *
    11162 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
    11163 * 1) neighboring items which exceed the capacity together => one clique
    11164 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
    11165 */
    11166static
    11168 SCIP*const scip, /**< SCIP data structure */
    11169 SCIP_VAR** items, /**< array of variable items */
    11170 SCIP_Longint* weights, /**< weights of the items */
    11171 int nitems, /**< the number of items */
    11172 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
    11173 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
    11174 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
    11175 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
    11176 int*const nbdchgs /**< pointer to count the number of performed bound changes */
    11177 )
    11178{
    11179 SCIP_Longint lastweight;
    11180 int ncliquevars;
    11181 int i;
    11182 int thisnbdchgs;
    11183
    11184 if( nitems <= 1 )
    11185 return SCIP_OKAY;
    11186
    11187 /* sort possible gain per substitution of the clique members */
    11188 if( ! sorteditems )
    11189 SCIPsortDownLongPtr(weights,(void**) items, nitems);
    11190
    11191 ncliquevars = 1;
    11192 lastweight = weights[0];
    11193
    11194 /* taking these two weights together violates the knapsack => include into clique */
    11195 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
    11196 {
    11197 lastweight = weights[i];
    11198 ++ncliquevars;
    11199 }
    11200
    11201 if( ncliquevars > 1 )
    11202 {
    11203 SCIP_Longint compareweight;
    11204 SCIP_VAR** cliquevars;
    11205 int compareweightidx;
    11206 int minclqsize;
    11207 int nnzadded;
    11208
    11209 /* add the clique to the clique table */
    11210 SCIPdebug( printClique(items, ncliquevars) );
    11211 SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
    11212
    11213 if( *cutoff )
    11214 return SCIP_OKAY;
    11215
    11216 *nbdchgs += thisnbdchgs;
    11217 nnzadded = ncliquevars;
    11218
    11219 /* no more cliques to be found (don't know if this can actually happen, since the knapsack could be replaced by a set-packing constraint)*/
    11220 if( ncliquevars == nitems )
    11221 return SCIP_OKAY;
    11222
    11223 /* copy items in order into buffer array and deduce more cliques */
    11224 SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
    11225
    11226 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
    11227 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
    11228 compareweightidx = ncliquevars - 2;
    11229 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
    11230
    11231 /* determine minimum clique size for the following loop */
    11232 minclqsize = (int)(cliqueextractfactor * ncliquevars);
    11233 minclqsize = MAX(minclqsize, 2);
    11234
    11235 /* loop over the remaining variables and the larger items of the first clique until we
    11236 * find another clique or reach the size limit */
    11237 while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
    11238 && ncliquevars >= minclqsize /* stop at a given minimum clique size */
    11239 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
    11240 )
    11241 {
    11242 compareweight = weights[compareweightidx];
    11243 assert(compareweight > 0);
    11244
    11245 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
    11246 if( compareweight + weights[i] > capacity )
    11247 {
    11248 assert(compareweightidx == ncliquevars -2);
    11249 cliquevars[ncliquevars - 1] = items[i];
    11250 SCIPdebug( printClique(cliquevars, ncliquevars) );
    11251 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
    11252
    11253 nnzadded += ncliquevars;
    11254
    11255 /* stop when there is a cutoff */
    11256 if( ! (*cutoff) )
    11257 *nbdchgs += thisnbdchgs;
    11258
    11259 /* go to next smaller item */
    11260 ++i;
    11261 }
    11262 else
    11263 {
    11264 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
    11265 compareweightidx--;
    11266 ncliquevars --;
    11267 }
    11268 }
    11269
    11270 SCIPfreeBufferArray(scip, &cliquevars);
    11271 }
    11272
    11273 return SCIP_OKAY;
    11274}
    11275
    11276/** adds cliques of the knapsack constraint to the global clique table */
    11277static
    11279 SCIP*const scip, /**< SCIP data structure */
    11280 SCIP_CONS*const cons, /**< knapsack constraint */
    11281 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
    11282 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
    11283 int*const nbdchgs /**< pointer to count the number of performed bound changes */
    11284 )
    11285{
    11286 SCIP_CONSDATA* consdata;
    11287 SCIP_CONSHDLRDATA* conshdlrdata;
    11288 int i;
    11289 SCIP_Longint minactduetonegcliques;
    11290 SCIP_Longint freecapacity;
    11291 int nnegcliques;
    11292 int cliquenum;
    11293 SCIP_VAR** poscliquevars;
    11294 SCIP_Longint* gainweights;
    11295 int nposcliquevars;
    11296 SCIP_Longint* secondmaxweights;
    11297 int nvars;
    11298
    11299 assert(scip != NULL);
    11300 assert(cons != NULL);
    11301 assert(cutoff != NULL);
    11302 assert(nbdchgs != NULL);
    11303
    11304 *cutoff = FALSE;
    11305
    11306 consdata = SCIPconsGetData(cons);
    11307 assert(consdata != NULL);
    11308
    11309 nvars = consdata->nvars;
    11310
    11311 /* check whether the cliques have already been added */
    11312 if( consdata->cliquesadded || nvars == 0 )
    11313 return SCIP_OKAY;
    11314
    11315 /* make sure, the items are merged */
    11316 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    11317 if( *cutoff )
    11318 return SCIP_OKAY;
    11319
    11320 /* make sure, the items are sorted by non-increasing weight */
    11321 sortItems(consdata);
    11322
    11323 assert(consdata->merged);
    11324
    11325 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    11326 assert(conshdlrdata != NULL);
    11327
    11328 /* calculate a clique partition */
    11329 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
    11330 nnegcliques = consdata->nnegcliques;
    11331 assert(nnegcliques <= nvars);
    11332
    11333 /* get temporary memory */
    11334 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
    11335 SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
    11336 BMSclearMemoryArray(gainweights, nvars);
    11337 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
    11338 BMSclearMemoryArray(secondmaxweights, nnegcliques);
    11339
    11340 minactduetonegcliques = 0;
    11341
    11342 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
    11343 if( nnegcliques < nvars )
    11344 {
    11345 nnegcliques = 0;
    11346
    11347 for( i = 0; i < nvars; ++i )
    11348 {
    11349 SCIP_Longint weight;
    11350
    11351 cliquenum = consdata->negcliquepartition[i];
    11352 assert(0 <= cliquenum && cliquenum <= nnegcliques);
    11353
    11354 weight = consdata->weights[i];
    11355 assert(weight > 0);
    11356
    11357 if( cliquenum == nnegcliques )
    11358 nnegcliques++;
    11359 else
    11360 {
    11361 minactduetonegcliques += weight;
    11362 if( secondmaxweights[cliquenum] == 0 )
    11363 secondmaxweights[cliquenum] = weight;
    11364 }
    11365 }
    11366 }
    11367
    11368 /* add cliques, using negated cliques information */
    11369 if( minactduetonegcliques > 0 )
    11370 {
    11371 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
    11372 freecapacity = consdata->capacity - minactduetonegcliques;
    11373
    11375 SCIPdebugMsg(scip, "Try to add cliques in knapsack constraint handler for constraint %s; capacity = %" SCIP_LONGINT_FORMAT ", minactivity(due to neg. cliques) = %" SCIP_LONGINT_FORMAT ", freecapacity = %" SCIP_LONGINT_FORMAT ".\n",
    11376 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
    11377
    11378 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
    11379 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
    11380
    11381 if( *cutoff )
    11382 goto TERMINATE;
    11383
    11384 nposcliquevars = 0;
    11385
    11386 for( i = nvars - 1; i >= 0; --i )
    11387 {
    11388 /* if we would take the biggest weight instead of the second biggest */
    11389 cliquenum = consdata->negcliquepartition[i];
    11390 if( consdata->weights[i] > secondmaxweights[cliquenum] )
    11391 {
    11392 poscliquevars[nposcliquevars] = consdata->vars[i];
    11393 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
    11394 ++nposcliquevars;
    11395 }
    11396 }
    11397
    11398 /* use the gain weights and free capacity to derive greedily cliques */
    11399 if( nposcliquevars > 1 )
    11400 {
    11401 SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
    11402
    11403 if( *cutoff )
    11404 goto TERMINATE;
    11405 }
    11406 }
    11407
    11408 /* build cliques by using the items with the maximal weights */
    11409 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
    11410
    11411 TERMINATE:
    11412 /* free temporary memory and mark the constraint */
    11413 SCIPfreeBufferArray(scip, &secondmaxweights);
    11414 SCIPfreeBufferArray(scip, &gainweights);
    11415 SCIPfreeBufferArray(scip, &poscliquevars);
    11416 consdata->cliquesadded = TRUE;
    11417
    11418 return SCIP_OKAY;
    11419}
    11420
    11421
    11422/** gets the key of the given element */
    11423static
    11424SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
    11425{ /*lint --e{715}*/
    11426 /* the key is the element itself */
    11427 return elem;
    11428}
    11429
    11430/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
    11431 * same coefficients
    11432 */
    11433static
    11434SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
    11435{
    11436#ifndef NDEBUG
    11437 SCIP* scip;
    11438#endif
    11439 SCIP_CONSDATA* consdata1;
    11440 SCIP_CONSDATA* consdata2;
    11441 int i;
    11442
    11443 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
    11444 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
    11445 assert(consdata1->sorted);
    11446 assert(consdata2->sorted);
    11447#ifndef NDEBUG
    11448 scip = (SCIP*)userptr;
    11449 assert(scip != NULL);
    11450#endif
    11451
    11452 /* checks trivial case */
    11453 if( consdata1->nvars != consdata2->nvars )
    11454 return FALSE;
    11455
    11456 for( i = consdata1->nvars - 1; i >= 0; --i )
    11457 {
    11458 /* tests if variables are equal */
    11459 if( consdata1->vars[i] != consdata2->vars[i] )
    11460 {
    11461 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
    11462 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
    11463 return FALSE;
    11464 }
    11465 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
    11466
    11467 /* tests if weights are equal too */
    11468 if( consdata1->weights[i] != consdata2->weights[i] )
    11469 return FALSE;
    11470 }
    11471
    11472 return TRUE;
    11473}
    11474
    11475/** returns the hash value of the key */
    11476static
    11477SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
    11478{
    11479#ifndef NDEBUG
    11480 SCIP* scip;
    11481#endif
    11482 SCIP_CONSDATA* consdata;
    11483 uint64_t firstweight;
    11484 int minidx;
    11485 int mididx;
    11486 int maxidx;
    11487
    11488 consdata = SCIPconsGetData((SCIP_CONS*)key);
    11489 assert(consdata != NULL);
    11490 assert(consdata->nvars > 0);
    11491
    11492#ifndef NDEBUG
    11493 scip = (SCIP*)userptr;
    11494 assert(scip != NULL);
    11495#endif
    11496
    11497 /* sorts the constraints */
    11498 sortItems(consdata);
    11499
    11500 minidx = SCIPvarGetIndex(consdata->vars[0]);
    11501 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
    11502 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
    11503 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
    11504
    11505 /* hash value depends on vectors of variable indices */
    11506 firstweight = (uint64_t)consdata->weights[0];
    11507 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
    11508}
    11509
    11510/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
    11511 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
    11512 */
    11513static
    11515 SCIP* scip, /**< SCIP data structure */
    11516 BMS_BLKMEM* blkmem, /**< block memory */
    11517 SCIP_CONS** conss, /**< constraint set */
    11518 int nconss, /**< number of constraints in constraint set */
    11519 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
    11520 int* ndelconss /**< pointer to count number of deleted constraints */
    11521 )
    11522{
    11523 SCIP_HASHTABLE* hashtable;
    11524 int hashtablesize;
    11525 int c;
    11526
    11527 assert(scip != NULL);
    11528 assert(blkmem != NULL);
    11529 assert(conss != NULL);
    11530 assert(ndelconss != NULL);
    11531
    11532 /* create a hash table for the constraint set */
    11533 hashtablesize = nconss;
    11534 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
    11535 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
    11536 hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
    11537
    11538 /* check all constraints in the given set for redundancy */
    11539 for( c = nconss - 1; c >= 0; --c )
    11540 {
    11541 SCIP_CONS* cons0;
    11542 SCIP_CONS* cons1;
    11543 SCIP_CONSDATA* consdata0;
    11544
    11545 cons0 = conss[c];
    11546
    11547 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
    11548 continue;
    11549
    11550 consdata0 = SCIPconsGetData(cons0);
    11551 assert(consdata0 != NULL);
    11552 if( consdata0->nvars == 0 )
    11553 {
    11554 if( consdata0->capacity < 0 )
    11555 {
    11556 *cutoff = TRUE;
    11557 goto TERMINATE;
    11558 }
    11559 else
    11560 {
    11561 SCIP_CALL( SCIPdelCons(scip, cons0) );
    11562 ++(*ndelconss);
    11563 continue;
    11564 }
    11565 }
    11566
    11567 /* get constraint from current hash table with same variables and same weights as cons0 */
    11568 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
    11569
    11570 if( cons1 != NULL )
    11571 {
    11572 SCIP_CONS* consstay;
    11573 SCIP_CONS* consdel;
    11574 SCIP_CONSDATA* consdata1;
    11575
    11576 assert(SCIPconsIsActive(cons1));
    11577 assert(!SCIPconsIsModifiable(cons1));
    11578
    11579 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
    11580 * delete old constraints afterwards
    11581 */
    11582 consdata1 = SCIPconsGetData(cons1);
    11583
    11584 assert(consdata1 != NULL);
    11585 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
    11586
    11587 assert(consdata0->sorted && consdata1->sorted);
    11588 assert(consdata0->vars[0] == consdata1->vars[0]);
    11589 assert(consdata0->weights[0] == consdata1->weights[0]);
    11590
    11591 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
    11592 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
    11593
    11594 /* check which constraint has to stay; */
    11595 if( consdata0->capacity < consdata1->capacity )
    11596 {
    11597 consstay = cons0;
    11598 consdel = cons1;
    11599
    11600 /* exchange consdel with consstay in hashtable */
    11601 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
    11602 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
    11603 }
    11604 else
    11605 {
    11606 consstay = cons1;
    11607 consdel = cons0;
    11608 }
    11609
    11610 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
    11611 SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
    11612
    11613 /* delete consdel */
    11614 SCIP_CALL( SCIPdelCons(scip, consdel) );
    11615 ++(*ndelconss);
    11616
    11617 assert(SCIPconsIsActive(consstay));
    11618 }
    11619 else
    11620 {
    11621 /* no such constraint in current hash table: insert cons0 into hash table */
    11622 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
    11623 }
    11624 }
    11625
    11626 TERMINATE:
    11627 /* free hash table */
    11628 SCIPhashtableFree(&hashtable);
    11629
    11630 return SCIP_OKAY;
    11631}
    11632
    11633
    11634/** compares constraint with all prior constraints for possible redundancy or aggregation,
    11635 * and removes or changes constraint accordingly
    11636 */
    11637static
    11639 SCIP* scip, /**< SCIP data structure */
    11640 SCIP_CONS** conss, /**< constraint set */
    11641 int firstchange, /**< first constraint that changed since last pair preprocessing round */
    11642 int chkind, /**< index of constraint to check against all prior indices upto startind */
    11643 int* ndelconss /**< pointer to count number of deleted constraints */
    11644 )
    11645{
    11646 SCIP_CONS* cons0;
    11647 SCIP_CONSDATA* consdata0;
    11648 int c;
    11649
    11650 assert(scip != NULL);
    11651 assert(conss != NULL);
    11652 assert(firstchange <= chkind);
    11653 assert(ndelconss != NULL);
    11654
    11655 /* get the constraint to be checked against all prior constraints */
    11656 cons0 = conss[chkind];
    11657 assert(cons0 != NULL);
    11658 assert(SCIPconsIsActive(cons0));
    11659 assert(!SCIPconsIsModifiable(cons0));
    11660
    11661 consdata0 = SCIPconsGetData(cons0);
    11662 assert(consdata0 != NULL);
    11663 assert(consdata0->nvars >= 1);
    11664 assert(consdata0->merged);
    11665
    11666 /* sort the constraint */
    11667 sortItems(consdata0);
    11668
    11669 /* see #2970 */
    11670 if( consdata0->capacity == 0 )
    11671 return SCIP_OKAY;
    11672
    11673 /* check constraint against all prior constraints */
    11674 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
    11675 {
    11676 SCIP_CONS* cons1;
    11677 SCIP_CONSDATA* consdata1;
    11678 SCIP_Bool iscons0incons1contained;
    11679 SCIP_Bool iscons1incons0contained;
    11680 SCIP_Real quotient;
    11681 int v;
    11682 int v0;
    11683 int v1;
    11684
    11685 cons1 = conss[c];
    11686 assert(cons1 != NULL);
    11687 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
    11688 continue;
    11689
    11690 consdata1 = SCIPconsGetData(cons1);
    11691 assert(consdata1 != NULL);
    11692
    11693 /* if both constraints didn't change since last pair processing, we can ignore the pair */
    11694 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
    11695 continue;
    11696
    11697 assert(consdata1->nvars >= 1);
    11698 assert(consdata1->merged);
    11699
    11700 /* sort the constraint */
    11701 sortItems(consdata1);
    11702
    11703 /* see #2970 */
    11704 if( consdata1->capacity == 0 )
    11705 continue;
    11706
    11707 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
    11708
    11709 if( consdata0->nvars > consdata1->nvars )
    11710 {
    11711 iscons0incons1contained = FALSE;
    11712 iscons1incons0contained = TRUE;
    11713 v = consdata1->nvars - 1;
    11714 }
    11715 else if( consdata0->nvars < consdata1->nvars )
    11716 {
    11717 iscons0incons1contained = TRUE;
    11718 iscons1incons0contained = FALSE;
    11719 v = consdata0->nvars - 1;
    11720 }
    11721 else
    11722 {
    11723 iscons0incons1contained = TRUE;
    11724 iscons1incons0contained = TRUE;
    11725 v = consdata0->nvars - 1;
    11726 }
    11727
    11728 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
    11729
    11730 /* check consdata0 against consdata1:
    11731 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
    11732 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
    11733 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
    11734 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
    11735 */
    11736 v0 = consdata0->nvars - 1;
    11737 v1 = consdata1->nvars - 1;
    11738
    11739 while( v >= 0 )
    11740 {
    11741 assert(iscons0incons1contained || iscons1incons0contained);
    11742
    11743 /* now there are more variables in cons1 left */
    11744 if( v1 > v0 )
    11745 {
    11746 iscons1incons0contained = FALSE;
    11747 if( !iscons0incons1contained )
    11748 break;
    11749 }
    11750 /* now there are more variables in cons0 left */
    11751 else if( v1 < v0 )
    11752 {
    11753 iscons0incons1contained = FALSE;
    11754 if( !iscons1incons0contained )
    11755 break;
    11756 }
    11757
    11758 assert(v == v0 || v == v1);
    11759 assert(v0 >= 0);
    11760 assert(v1 >= 0);
    11761
    11762 /* both variables are the same */
    11763 if( consdata0->vars[v0] == consdata1->vars[v1] )
    11764 {
    11765 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
    11766 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
    11767 {
    11768 iscons1incons0contained = FALSE;
    11769 if( !iscons0incons1contained )
    11770 break;
    11771 }
    11772 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
    11773 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
    11774 {
    11775 iscons0incons1contained = FALSE;
    11776 if( !iscons1incons0contained )
    11777 break;
    11778 }
    11779 --v0;
    11780 --v1;
    11781 --v;
    11782 }
    11783 else
    11784 {
    11785 /* both constraints have a variables which is not part of the other constraint, so stop */
    11786 if( iscons0incons1contained && iscons1incons0contained )
    11787 {
    11788 iscons0incons1contained = FALSE;
    11789 iscons1incons0contained = FALSE;
    11790 break;
    11791 }
    11792 assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
    11793 assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
    11794 /* continue to the next variable */
    11795 if( iscons0incons1contained )
    11796 --v1;
    11797 else
    11798 --v0;
    11799 }
    11800 }
    11801 /* neither one constraint was contained in another or we checked all variables of one constraint against the
    11802 * other
    11803 */
    11804 assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
    11805
    11806 if( iscons1incons0contained )
    11807 {
    11808 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
    11809 SCIPdebugPrintCons(scip, cons1, NULL);
    11810
    11811 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
    11812 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
    11813
    11814 SCIP_CALL( SCIPdelCons(scip, cons1) );
    11815 ++(*ndelconss);
    11816 }
    11817 else if( iscons0incons1contained )
    11818 {
    11819 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
    11820 SCIPdebugPrintCons(scip, cons0, NULL);
    11821
    11822 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
    11823 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
    11824
    11825 SCIP_CALL( SCIPdelCons(scip, cons0) );
    11826 ++(*ndelconss);
    11827 break;
    11828 }
    11829 }
    11830
    11831 return SCIP_OKAY;
    11832}
    11833
    11834/** helper function to enforce constraints */
    11835static
    11837 SCIP* scip, /**< SCIP data structure */
    11838 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    11839 SCIP_CONS** conss, /**< constraints to process */
    11840 int nconss, /**< number of constraints */
    11841 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
    11842 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    11843 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    11844 )
    11845{
    11846 SCIP_CONSHDLRDATA* conshdlrdata;
    11847 SCIP_Bool violated;
    11848 SCIP_Bool cutoff = FALSE;
    11849 int maxncuts;
    11850 int ncuts = 0;
    11851 int i;
    11852
    11853 *result = SCIP_FEASIBLE;
    11854
    11855 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
    11856 sol == NULL ? "LP" : "relaxation");
    11857
    11858 /* get maximal number of cuts per round */
    11859 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11860 assert(conshdlrdata != NULL);
    11861 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
    11862
    11863 /* search for violated useful knapsack constraints */
    11864 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
    11865 {
    11866 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
    11867 if( violated )
    11868 {
    11869 /* add knapsack constraint as LP row to the relaxation */
    11870 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
    11871 ncuts++;
    11872 }
    11873 }
    11874
    11875 /* as long as no violations were found, search for violated obsolete knapsack constraints */
    11876 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
    11877 {
    11878 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
    11879 if( violated )
    11880 {
    11881 /* add knapsack constraint as LP row to the relaxation */
    11882 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
    11883 ncuts++;
    11884 }
    11885 }
    11886
    11887 /* adjust the result code */
    11888 if ( cutoff )
    11889 *result = SCIP_CUTOFF;
    11890 else if ( ncuts > 0 )
    11891 *result = SCIP_SEPARATED;
    11892
    11893 return SCIP_OKAY;
    11894}
    11895
    11896/*
    11897 * Linear constraint upgrading
    11898 */
    11899
    11900/** creates and captures a knapsack constraint out of a linear inequality */
    11901static
    11903 SCIP* scip, /**< SCIP data structure */
    11904 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    11905 const char* name, /**< name of constraint */
    11906 int nvars, /**< number of variables in the constraint */
    11907 SCIP_VAR** vars, /**< array with variables of constraint entries */
    11908 SCIP_Real* vals, /**< array with inequality coefficients */
    11909 SCIP_Real lhs, /**< left hand side of inequality */
    11910 SCIP_Real rhs, /**< right hand side of inequality */
    11911 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    11912 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    11913 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    11914 * Usually set to TRUE. */
    11915 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    11916 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    11917 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    11918 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    11919 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    11920 * Usually set to TRUE. */
    11921 SCIP_Bool local, /**< is constraint only valid locally?
    11922 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    11923 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    11924 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    11925 * adds coefficients to this constraint. */
    11926 SCIP_Bool dynamic, /**< is constraint subject to aging?
    11927 * Usually set to FALSE. Set to TRUE for own cuts which
    11928 * are separated as constraints. */
    11929 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    11930 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    11931 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    11932 * if it may be moved to a more global node?
    11933 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    11934 )
    11935{
    11936 SCIP_VAR** transvars;
    11937 SCIP_Longint* weights;
    11938 SCIP_Longint capacity;
    11939 SCIP_Longint weight;
    11940 int mult;
    11941 int v;
    11942
    11943 assert(nvars == 0 || vars != NULL);
    11944 assert(nvars == 0 || vals != NULL);
    11945 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
    11946
    11947 /* get temporary memory */
    11948 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
    11950
    11951 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
    11952 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
    11953 */
    11954 if( SCIPisInfinity(scip, rhs) )
    11955 {
    11956 mult = -1;
    11957 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
    11958 }
    11959 else
    11960 {
    11961 mult = +1;
    11962 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
    11963 }
    11964
    11965 /* negate positive or negative variables */
    11966 for( v = 0; v < nvars; ++v )
    11967 {
    11968 assert(SCIPisFeasIntegral(scip, vals[v]));
    11969 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
    11970 if( weight > 0 )
    11971 {
    11972 transvars[v] = vars[v];
    11973 weights[v] = weight;
    11974 }
    11975 else
    11976 {
    11977 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
    11978 weights[v] = -weight; /*lint !e2704*/
    11979 capacity -= weight;
    11980 }
    11981 assert(transvars[v] != NULL);
    11982 }
    11983
    11984 /* create the constraint */
    11985 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
    11986 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    11987
    11988 /* free temporary memory */
    11989 SCIPfreeBufferArray(scip, &weights);
    11990 SCIPfreeBufferArray(scip, &transvars);
    11991
    11992 return SCIP_OKAY;
    11993}
    11994
    11995/** tries to upgrade a linear constraint into a knapsack constraint */
    11996static
    11997SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
    11998{ /*lint --e{715}*/
    11999 SCIP_Bool upgrade;
    12000
    12001 assert(upgdcons != NULL);
    12002
    12003 /* check, if linear constraint can be upgraded to a knapsack constraint
    12004 * - all variables must be binary
    12005 * - all coefficients must be integral
    12006 * - exactly one of the sides must be infinite
    12007 * note that this includes the case of negative capacity, which has been
    12008 * observed to occur, e.g., when upgrading a conflict constraint
    12009 */
    12010 upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
    12011 && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
    12012 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
    12013
    12014 if( upgrade )
    12015 {
    12016 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
    12017
    12018 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
    12019 assert(!SCIPconsIsModifiable(cons));
    12020 SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
    12025 }
    12026
    12027 return SCIP_OKAY;
    12028}
    12029
    12030/** adds symmetry information of constraint to a symmetry detection graph */
    12031static
    12033 SCIP* scip, /**< SCIP pointer */
    12034 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
    12035 SCIP_CONS* cons, /**< constraint */
    12036 SYM_GRAPH* graph, /**< symmetry detection graph */
    12037 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
    12038 )
    12039{
    12040 SCIP_CONSDATA* consdata;
    12041 SCIP_VAR** vars;
    12042 SCIP_Real* vals;
    12043 SCIP_Real constant = 0.0;
    12044 SCIP_Real rhs;
    12045 int nlocvars;
    12046 int nvars;
    12047 int i;
    12048
    12049 assert(scip != NULL);
    12050 assert(cons != NULL);
    12051 assert(graph != NULL);
    12052 assert(success != NULL);
    12053
    12054 consdata = SCIPconsGetData(cons);
    12055 assert(consdata != NULL);
    12056 assert(graph != NULL);
    12057
    12058 /* get active variables of the constraint */
    12060 nlocvars = consdata->nvars;
    12061
    12064
    12065 for( i = 0; i < consdata->nvars; ++i )
    12066 {
    12067 vars[i] = consdata->vars[i];
    12068 vals[i] = (SCIP_Real) consdata->weights[i];
    12069 }
    12070
    12071 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
    12072 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
    12073
    12074 SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars,
    12075 cons, -SCIPinfinity(scip), rhs, success) );
    12076
    12077 SCIPfreeBufferArray(scip, &vals);
    12078 SCIPfreeBufferArray(scip, &vars);
    12079
    12080 return SCIP_OKAY;
    12081}
    12082
    12083/*
    12084 * Callback methods of constraint handler
    12085 */
    12086
    12087/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    12088/**! [SnippetConsCopyKnapsack] */
    12089static
    12090SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
    12091{ /*lint --e{715}*/
    12092 assert(scip != NULL);
    12093 assert(conshdlr != NULL);
    12094 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12095
    12096 /* call inclusion method of constraint handler */
    12098
    12099 *valid = TRUE;
    12100
    12101 return SCIP_OKAY;
    12102}
    12103/**! [SnippetConsCopyKnapsack] */
    12104
    12105/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    12106/**! [SnippetConsFreeKnapsack] */
    12107static
    12108SCIP_DECL_CONSFREE(consFreeKnapsack)
    12109{ /*lint --e{715}*/
    12110 SCIP_CONSHDLRDATA* conshdlrdata;
    12111
    12112 /* free constraint handler data */
    12113 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12114 assert(conshdlrdata != NULL);
    12115
    12116 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->probtoidxmap, conshdlrdata->probtoidxmapsize);
    12117 SCIPfreeBlockMemory(scip, &conshdlrdata);
    12118
    12119 SCIPconshdlrSetData(conshdlr, NULL);
    12120
    12121 return SCIP_OKAY;
    12122}
    12123/**! [SnippetConsFreeKnapsack] */
    12124
    12125
    12126/** initialization method of constraint handler (called after problem was transformed) */
    12127static
    12128SCIP_DECL_CONSINIT(consInitKnapsack)
    12129{ /*lint --e{715}*/
    12130 SCIP_CONSHDLRDATA* conshdlrdata;
    12131 int nvars;
    12132
    12133 assert( scip != NULL );
    12134 assert( conshdlr != NULL );
    12135
    12136 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12137 assert(conshdlrdata != NULL);
    12138
    12139 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
    12141
    12142 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
    12143 conshdlrdata->reals1size = nvars;
    12144
    12145 return SCIP_OKAY;
    12146}
    12147
    12148/** deinitialization method of constraint handler (called before transformed problem is freed) */
    12149static
    12150SCIP_DECL_CONSEXIT(consExitKnapsack)
    12151{ /*lint --e{715}*/
    12152 SCIP_CONSHDLRDATA* conshdlrdata;
    12153
    12154 assert( scip != NULL );
    12155 assert( conshdlr != NULL );
    12156
    12157 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12158 assert(conshdlrdata != NULL);
    12159
    12160 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
    12161 conshdlrdata->reals1size = 0;
    12162
    12163 return SCIP_OKAY;
    12164}
    12165
    12166
    12167/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    12168static
    12169SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
    12170{ /*lint --e{715}*/
    12171 SCIP_CONSHDLRDATA* conshdlrdata;
    12172 int nvars;
    12173
    12174 assert(scip != NULL);
    12175 assert(conshdlr != NULL);
    12176 assert(nconss == 0 || conss != NULL);
    12177
    12178 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12179 assert(conshdlrdata != NULL);
    12180
    12181 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
    12183
    12184 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
    12185 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
    12186 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
    12187 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
    12188 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
    12189 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
    12190 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
    12191 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
    12192
    12193 conshdlrdata->ints1size = nvars;
    12194 conshdlrdata->ints2size = nvars;
    12195 conshdlrdata->longints1size = nvars;
    12196 conshdlrdata->longints2size = nvars;
    12197 conshdlrdata->bools1size = nvars;
    12198 conshdlrdata->bools2size = nvars;
    12199 conshdlrdata->bools3size = nvars;
    12200 conshdlrdata->bools4size = nvars;
    12201
    12202#ifdef WITH_CARDINALITY_UPGRADE
    12203 conshdlrdata->upgradedcard = FALSE;
    12204#endif
    12205
    12206 return SCIP_OKAY;
    12207}
    12208
    12209
    12210/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
    12211static
    12212SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
    12213{ /*lint --e{715}*/
    12214 SCIP_CONSHDLRDATA* conshdlrdata;
    12215 int c;
    12216
    12217 assert(scip != NULL);
    12218 assert(conshdlr != NULL);
    12219
    12220 for( c = 0; c < nconss; ++c )
    12221 {
    12222 if( !SCIPconsIsDeleted(conss[c]) )
    12223 {
    12224 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
    12225 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
    12226 }
    12227 }
    12228
    12229 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12230 assert(conshdlrdata != NULL);
    12231
    12232 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
    12233 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
    12234 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
    12235 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
    12236 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
    12237 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
    12238 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
    12239 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
    12240
    12241 conshdlrdata->ints1size = 0;
    12242 conshdlrdata->ints2size = 0;
    12243 conshdlrdata->longints1size = 0;
    12244 conshdlrdata->longints2size = 0;
    12245 conshdlrdata->bools1size = 0;
    12246 conshdlrdata->bools2size = 0;
    12247 conshdlrdata->bools3size = 0;
    12248 conshdlrdata->bools4size = 0;
    12249
    12250 return SCIP_OKAY;
    12251}
    12252
    12253/** solving process initialization method of constraint handler */
    12254static
    12255SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
    12256{ /*lint --e{715}*/
    12257 /* add nlrow representation to NLP, if NLP had been constructed */
    12259 {
    12260 int c;
    12261 for( c = 0; c < nconss; ++c )
    12262 {
    12263 SCIP_CALL( addNlrow(scip, conss[c]) );
    12264 }
    12265 }
    12266
    12267 return SCIP_OKAY;
    12268}
    12269
    12270/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    12271static
    12272SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
    12273{ /*lint --e{715}*/
    12274 SCIP_CONSDATA* consdata;
    12275 int c;
    12276
    12277 assert( scip != NULL );
    12278
    12279 /* release the rows and nlrows of all constraints */
    12280 for( c = 0; c < nconss; ++c )
    12281 {
    12282 consdata = SCIPconsGetData(conss[c]);
    12283 assert(consdata != NULL);
    12284
    12285 if( consdata->row != NULL )
    12286 {
    12287 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
    12288 }
    12289
    12290 if( consdata->nlrow != NULL )
    12291 {
    12292 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
    12293 }
    12294 }
    12295
    12296 return SCIP_OKAY;
    12297}
    12298
    12299/** frees specific constraint data */
    12300static
    12301SCIP_DECL_CONSDELETE(consDeleteKnapsack)
    12302{ /*lint --e{715}*/
    12303 SCIP_CONSHDLRDATA* conshdlrdata;
    12304
    12305 assert(conshdlr != NULL);
    12306 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12307
    12308 /* get event handler */
    12309 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12310 assert(conshdlrdata != NULL);
    12311 assert(conshdlrdata->eventhdlr != NULL);
    12312
    12313 /* free knapsack constraint */
    12314 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
    12315
    12316 return SCIP_OKAY;
    12317}
    12318
    12319/** transforms constraint data into data belonging to the transformed problem */
    12320/**! [SnippetConsTransKnapsack]*/
    12321static
    12322SCIP_DECL_CONSTRANS(consTransKnapsack)
    12323{ /*lint --e{715}*/
    12324 SCIP_CONSHDLRDATA* conshdlrdata;
    12325 SCIP_CONSDATA* sourcedata;
    12326 SCIP_CONSDATA* targetdata;
    12327
    12328 assert(conshdlr != NULL);
    12329 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    12331 assert(sourcecons != NULL);
    12332 assert(targetcons != NULL);
    12333
    12334 sourcedata = SCIPconsGetData(sourcecons);
    12335 assert(sourcedata != NULL);
    12336 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
    12337
    12338 /* get event handler */
    12339 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12340 assert(conshdlrdata != NULL);
    12341 assert(conshdlrdata->eventhdlr != NULL);
    12342
    12343 /* create target constraint data */
    12344 SCIP_CALL( consdataCreate(scip, &targetdata,
    12345 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
    12346
    12347 /* create target constraint */
    12348 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
    12349 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
    12350 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
    12351 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
    12352 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
    12353
    12354 /* catch events for variables */
    12355 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
    12356
    12357 return SCIP_OKAY;
    12358}
    12359/**! [SnippetConsTransKnapsack]*/
    12360
    12361/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
    12362static
    12363SCIP_DECL_CONSINITLP(consInitlpKnapsack)
    12364{ /*lint --e{715}*/
    12365 int i;
    12366
    12367 *infeasible = FALSE;
    12368
    12369 for( i = 0; i < nconss && !(*infeasible); i++ )
    12370 {
    12371 assert(SCIPconsIsInitial(conss[i]));
    12372 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
    12373 }
    12374
    12375 return SCIP_OKAY;
    12376}
    12377
    12378/** separation method of constraint handler for LP solutions */
    12379static
    12380SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
    12381{ /*lint --e{715}*/
    12382 SCIP_CONSHDLRDATA* conshdlrdata;
    12383 SCIP_Bool sepacardinality;
    12384 SCIP_Bool cutoff;
    12385
    12386 SCIP_Real loclowerbound;
    12387 SCIP_Real glblowerbound;
    12388 SCIP_Real cutoffbound;
    12389 SCIP_Real maxbound;
    12390
    12391 int depth;
    12392 int nrounds;
    12393 int sepafreq;
    12394 int sepacardfreq;
    12395 int ncuts;
    12396 int maxsepacuts;
    12397 int i;
    12398
    12399 *result = SCIP_DIDNOTRUN;
    12400
    12401 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12402 assert(conshdlrdata != NULL);
    12403
    12404 depth = SCIPgetDepth(scip);
    12405 nrounds = SCIPgetNSepaRounds(scip);
    12406
    12407 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
    12408 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
    12409
    12410 /* only call the separator a given number of times at each node */
    12411 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
    12412 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
    12413 return SCIP_OKAY;
    12414
    12415 /* check, if we should additionally separate knapsack cuts */
    12416 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
    12417 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
    12418 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
    12419 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
    12420
    12421 /* check dual bound to see if we want to produce knapsack cuts at this node */
    12422 loclowerbound = SCIPgetLocalLowerbound(scip);
    12423 glblowerbound = SCIPgetLowerbound(scip);
    12424 cutoffbound = SCIPgetCutoffbound(scip);
    12425 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
    12426 sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
    12427 sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
    12428
    12429 /* get the maximal number of cuts allowed in a separation round */
    12430 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
    12431
    12432 *result = SCIP_DIDNOTFIND;
    12433 ncuts = 0;
    12434 cutoff = FALSE;
    12435
    12436 /* separate useful constraints */
    12437 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
    12438 {
    12439 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
    12440 }
    12441
    12442 /* adjust return value */
    12443 if ( cutoff )
    12444 *result = SCIP_CUTOFF;
    12445 else if ( ncuts > 0 )
    12446 *result = SCIP_SEPARATED;
    12447
    12448 return SCIP_OKAY;
    12449}
    12450
    12451
    12452/** separation method of constraint handler for arbitrary primal solutions */
    12453static
    12454SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
    12455{ /*lint --e{715}*/
    12456 SCIP_CONSHDLRDATA* conshdlrdata;
    12457 SCIP_Bool sepacardinality;
    12458 SCIP_Bool cutoff;
    12459
    12460 int depth;
    12461 int nrounds;
    12462 int sepafreq;
    12463 int sepacardfreq;
    12464 int ncuts;
    12465 int maxsepacuts;
    12466 int i;
    12467
    12468 *result = SCIP_DIDNOTRUN;
    12469
    12470 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12471 assert(conshdlrdata != NULL);
    12472
    12473 depth = SCIPgetDepth(scip);
    12474 nrounds = SCIPgetNSepaRounds(scip);
    12475
    12476 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
    12477 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
    12478
    12479 /* only call the separator a given number of times at each node */
    12480 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
    12481 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
    12482 return SCIP_OKAY;
    12483
    12484 /* check, if we should additionally separate knapsack cuts */
    12485 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
    12486 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
    12487 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
    12488 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
    12489
    12490 /* get the maximal number of cuts allowed in a separation round */
    12491 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
    12492
    12493 *result = SCIP_DIDNOTFIND;
    12494 ncuts = 0;
    12495 cutoff = FALSE;
    12496
    12497 /* separate useful constraints */
    12498 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
    12499 {
    12500 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
    12501 }
    12502
    12503 /* adjust return value */
    12504 if ( cutoff )
    12505 *result = SCIP_CUTOFF;
    12506 else if( ncuts > 0 )
    12507 *result = SCIP_SEPARATED;
    12508
    12509 return SCIP_OKAY;
    12510}
    12511
    12512/** constraint enforcing method of constraint handler for LP solutions */
    12513static
    12514SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
    12515{ /*lint --e{715}*/
    12516 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
    12517
    12518 return SCIP_OKAY;
    12519}
    12520
    12521/** constraint enforcing method of constraint handler for relaxation solutions */
    12522static
    12523SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
    12524{ /*lint --e{715}*/
    12525 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
    12526
    12527 return SCIP_OKAY;
    12528}
    12529
    12530/** constraint enforcing method of constraint handler for pseudo solutions */
    12531static
    12532SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
    12533{ /*lint --e{715}*/
    12534 SCIP_Bool violated;
    12535 int i;
    12536
    12537 for( i = 0; i < nconss; i++ )
    12538 {
    12539 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
    12540 if( violated )
    12541 {
    12542 *result = SCIP_INFEASIBLE;
    12543 return SCIP_OKAY;
    12544 }
    12545 }
    12546 *result = SCIP_FEASIBLE;
    12547
    12548 return SCIP_OKAY;
    12549}
    12550
    12551/** feasibility check method of constraint handler for integral solutions */
    12552static
    12553SCIP_DECL_CONSCHECK(consCheckKnapsack)
    12554{ /*lint --e{715}*/
    12555 SCIP_Bool violated;
    12556 int i;
    12557
    12558 *result = SCIP_FEASIBLE;
    12559
    12560 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
    12561 {
    12562 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
    12563 if( violated )
    12564 *result = SCIP_INFEASIBLE;
    12565 }
    12566
    12567 return SCIP_OKAY;
    12568}
    12569
    12570/** domain propagation method of constraint handler */
    12571static
    12572SCIP_DECL_CONSPROP(consPropKnapsack)
    12573{ /*lint --e{715}*/
    12574 SCIP_CONSHDLRDATA* conshdlrdata;
    12575 SCIP_Bool cutoff;
    12576 SCIP_Bool redundant;
    12577 SCIP_Bool inpresolve;
    12578 int nfixedvars;
    12579 int i;
    12580
    12581 cutoff = FALSE;
    12582 nfixedvars = 0;
    12583
    12584 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12585 assert(conshdlrdata != NULL);
    12586
    12587 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
    12588 assert(!inpresolve || SCIPinProbing(scip));
    12589
    12590 /* process useful constraints */
    12591 for( i = 0; i < nmarkedconss && !cutoff; i++ )
    12592 {
    12593 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
    12594 * otherwise the multi-aggregation should be resolved
    12595 */
    12596 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
    12597 continue;
    12598#ifndef NDEBUG
    12599 else
    12600 assert(!(SCIPconsGetData(conss[i])->existmultaggr));
    12601#endif
    12602
    12603 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
    12604
    12605 /* unmark the constraint to be propagated */
    12607 }
    12608
    12609 /* adjust result code */
    12610 if( cutoff )
    12611 *result = SCIP_CUTOFF;
    12612 else if( nfixedvars > 0 )
    12613 *result = SCIP_REDUCEDDOM;
    12614 else
    12615 *result = SCIP_DIDNOTFIND;
    12616
    12617 return SCIP_OKAY; /*lint !e438*/
    12618}
    12619
    12620/** presolving method of constraint handler */
    12621static
    12622SCIP_DECL_CONSPRESOL(consPresolKnapsack)
    12623{ /*lint --e{574,715}*/
    12624 SCIP_CONSHDLRDATA* conshdlrdata;
    12625 SCIP_CONSDATA* consdata;
    12626 SCIP_CONS* cons;
    12627 SCIP_Bool cutoff;
    12628 SCIP_Bool redundant;
    12629 SCIP_Bool success;
    12630 int oldnfixedvars;
    12631 int oldnchgbds;
    12632 int oldndelconss;
    12633 int oldnaddconss;
    12634 int oldnchgcoefs;
    12635 int oldnchgsides;
    12636 int firstchange;
    12637 int c;
    12638 SCIP_Bool newchanges;
    12639
    12640 /* remember old preprocessing counters */
    12641 cutoff = FALSE;
    12642 oldnfixedvars = *nfixedvars;
    12643 oldnchgbds = *nchgbds;
    12644 oldndelconss = *ndelconss;
    12645 oldnaddconss = *naddconss;
    12646 oldnchgcoefs = *nchgcoefs;
    12647 oldnchgsides = *nchgsides;
    12648 firstchange = INT_MAX;
    12649
    12650 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
    12651
    12652 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12653 assert(conshdlrdata != NULL);
    12654
    12655 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
    12656 {
    12657 int thisnfixedvars;
    12658 int thisnchgbds;
    12659
    12660 cons = conss[c];
    12661 consdata = SCIPconsGetData(cons);
    12662 assert(consdata != NULL);
    12663
    12664 /* update data structures */
    12665 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
    12666 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
    12667 {
    12668 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
    12669 if( cutoff )
    12670 break;
    12671 }
    12672
    12673 /* force presolving the constraint in the initial round */
    12674 if( nrounds == 0 )
    12675 consdata->presolvedtiming = 0;
    12676 else if( consdata->presolvedtiming >= presoltiming )
    12677 continue;
    12678
    12679 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
    12681 consdata->presolvedtiming = presoltiming;
    12682
    12683 thisnfixedvars = *nfixedvars;
    12684 thisnchgbds = *nchgbds;
    12685
    12686 /* merge constraint, so propagation works better */
    12687 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
    12688 if( cutoff )
    12689 break;
    12690
    12691 /* add cliques in the knapsack to the clique table */
    12692 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    12693 {
    12694 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
    12695 if( cutoff )
    12696 break;
    12697 }
    12698
    12699 /* propagate constraint */
    12700 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
    12701 {
    12702 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
    12703
    12704 if( cutoff )
    12705 break;
    12706 if( redundant )
    12707 {
    12708 (*ndelconss)++;
    12709 continue;
    12710 }
    12711 }
    12712
    12713 /* remove again all fixed variables, if further fixings were found */
    12714 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
    12715 {
    12716 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
    12717 if( cutoff )
    12718 break;
    12719
    12720 thisnfixedvars = *nfixedvars;
    12721 }
    12722
    12723 if( !SCIPconsIsModifiable(cons) )
    12724 {
    12725 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
    12726 if( consdata->weightsum <= consdata->capacity )
    12727 {
    12728 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
    12729 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
    12731 continue;
    12732 }
    12733
    12734 /* divide weights by their greatest common divisor */
    12735 normalizeWeights(cons, nchgcoefs, nchgsides);
    12736
    12737 /* try to simplify inequalities */
    12738 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    12739 {
    12740 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
    12741 if( cutoff )
    12742 break;
    12743
    12744 if( SCIPconsIsDeleted(cons) )
    12745 continue;
    12746
    12747 /* remove again all fixed variables, if further fixings were found */
    12748 if( *nfixedvars > thisnfixedvars )
    12749 {
    12750 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
    12751 if( cutoff )
    12752 break;
    12753 }
    12754 }
    12755
    12756 /* tighten capacity and weights */
    12757 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
    12758 if( cutoff )
    12759 break;
    12760
    12761 if( SCIPconsIsActive(cons) )
    12762 {
    12763 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    12764 {
    12765 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
    12766 * dual reduction
    12767 */
    12768 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
    12769 if( redundant )
    12770 continue;
    12771 }
    12772
    12773 /* check if knapsack constraint is parallel to objective function */
    12774 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
    12775 }
    12776 }
    12777 /* remember the first changed constraint to begin the next aggregation round with */
    12778 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
    12779 firstchange = c;
    12780 }
    12781
    12782 /* preprocess pairs of knapsack constraints */
    12783 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    12784 {
    12785 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
    12786 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
    12787 }
    12788
    12789 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
    12790 success = TRUE;
    12791 else
    12792 success = FALSE;
    12793
    12794 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    12795 {
    12796 SCIP_Longint npaircomparisons;
    12797
    12798 npaircomparisons = 0;
    12799 oldndelconss = *ndelconss;
    12800 oldnchgsides = *nchgsides;
    12801 oldnchgcoefs = *nchgcoefs;
    12802
    12803 for( c = firstchange; c < nconss && !SCIPisStopped(scip); ++c )
    12804 {
    12805 cons = conss[c];
    12806 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
    12807 continue;
    12808
    12809 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
    12810
    12811 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
    12812
    12813 if( npaircomparisons > NMINCOMPARISONS )
    12814 {
    12815 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
    12816 success = TRUE;
    12817 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
    12818 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
    12819 break;
    12820 oldndelconss = *ndelconss;
    12821 oldnchgsides = *nchgsides;
    12822 oldnchgcoefs = *nchgcoefs;
    12823 npaircomparisons = 0;
    12824 }
    12825 }
    12826 }
    12827#ifdef WITH_CARDINALITY_UPGRADE
    12828 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
    12829 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
    12830 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
    12831 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
    12832 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
    12833 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
    12834 * as well, we better keep this code disabled. */
    12835 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
    12836 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
    12837 {
    12838 SCIP_HASHMAP* varhash;
    12839 SCIP_VAR** cardvars;
    12840 SCIP_Real* cardweights;
    12841 int noldupgdconss;
    12842 int nscipvars;
    12843 int makeupgrade;
    12844
    12845 noldupgdconss = *nupgdconss;
    12846 nscipvars = SCIPgetNVars(scip);
    12847 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
    12848 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
    12849
    12850 /* set up hash map */
    12851 SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
    12852
    12853 /* We loop through all cardinality constraints twice:
    12854 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
    12855 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
    12856 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
    12857 * - Second, upgrade knapsack constraints to cardinality constraints. */
    12858 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
    12859 {
    12860 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
    12861 {
    12862 SCIP_CONS* cardcons;
    12863 SCIP_VAR** vars;
    12864 SCIP_Longint* weights;
    12865 int nvars;
    12866 int v;
    12867
    12868 cons = conss[c];
    12869 assert( cons != NULL );
    12870
    12871 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
    12872 continue;
    12873
    12874 consdata = SCIPconsGetData(cons);
    12875 assert( consdata != NULL );
    12876
    12877 nvars = consdata->nvars;
    12878 vars = consdata->vars;
    12879 weights = consdata->weights;
    12880
    12881 /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
    12882 * - all variables must be binary (always true)
    12883 * - all coefficients must be 1.0
    12884 * - the right hand side must be smaller than nvars
    12885 */
    12886 if ( consdata->capacity >= nvars )
    12887 continue;
    12888
    12889 /* the weights are sorted: check first and last weight */
    12890 assert( consdata->sorted );
    12891 if ( weights[0] != 1 || weights[nvars-1] != 1 )
    12892 continue;
    12893
    12894 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
    12895 for (v = 0; v < nvars; ++v)
    12896 {
    12897 SCIP_BOUNDTYPE* impltypes;
    12898 SCIP_Real* implbounds;
    12899 SCIP_VAR** implvars;
    12900 SCIP_VAR* var;
    12901 int nimpls;
    12902 int j;
    12903
    12904 var = consdata->vars[v];
    12905 assert( var != NULL );
    12906 assert( SCIPvarIsBinary(var) );
    12907
    12908 /* ignore non-active variables */
    12909 if ( ! SCIPvarIsActive(var) )
    12910 break;
    12911
    12912 /* be sure that implication variable has zero objective */
    12913 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
    12914 break;
    12915
    12916 nimpls = SCIPvarGetNImpls(var, FALSE);
    12917 implvars = SCIPvarGetImplVars(var, FALSE);
    12918 implbounds = SCIPvarGetImplBounds(var, FALSE);
    12919 impltypes = SCIPvarGetImplTypes(var, FALSE);
    12920
    12921 for (j = 0; j < nimpls; ++j)
    12922 {
    12923 /* be sure that continuous variable is fixed to 0 */
    12924 if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
    12925 continue;
    12926
    12927 /* cannot currently deal with nonzero fixings */
    12928 if ( ! SCIPisZero(scip, implbounds[j]) )
    12929 continue;
    12930
    12931 /* number of down locks should be one */
    12932 if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
    12933 continue;
    12934
    12935 cardvars[v] = implvars[j];
    12936 cardweights[v] = (SCIP_Real) v;
    12937
    12938 break;
    12939 }
    12940
    12941 /* found no variable upper bound candidate -> exit */
    12942 if ( j >= nimpls )
    12943 break;
    12944 }
    12945
    12946 /* did not find fitting variable upper bound for some variable -> exit */
    12947 if ( v < nvars )
    12948 break;
    12949
    12950 /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
    12951 * in which the binary variable is involved in */
    12952 if ( makeupgrade == 0 )
    12953 {
    12954 for (v = 0; v < nvars; ++v)
    12955 {
    12956 if ( SCIPhashmapExists(varhash, vars[v]) )
    12957 {
    12958 int image;
    12959
    12960 image = SCIPhashmapGetImageInt(varhash, vars[v]);
    12961 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
    12962 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
    12963 }
    12964 else
    12965 {
    12966 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
    12967 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
    12968 assert( SCIPhashmapExists(varhash, vars[v]) );
    12969 }
    12970 }
    12971 }
    12972 else
    12973 {
    12974 SCIP_CONS* origcons;
    12975
    12976 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
    12977 * knapsack constraint coincides with the number of variable up locks */
    12978 for (v = 0; v < nvars; ++v)
    12979 {
    12980 assert( SCIPhashmapExists(varhash, vars[v]) );
    12981 if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
    12982 break;
    12983 }
    12984 if ( v < nvars )
    12985 break;
    12986
    12987 /* store that we have upgraded */
    12988 conshdlrdata->upgradedcard = TRUE;
    12989
    12990 /* at this point we found suitable variable upper bounds */
    12991 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
    12992
    12993 /* create cardinality constraint */
    12994 assert( ! SCIPconsIsModifiable(cons) );
    12995 SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
    12999#ifdef SCIP_DEBUG
    13000 SCIPprintCons(scip, cons, NULL);
    13001 SCIPinfoMessage(scip, NULL, "\n");
    13002 SCIPprintCons(scip, cardcons, NULL);
    13003 SCIPinfoMessage(scip, NULL, "\n");
    13004#endif
    13005 /* add the upgraded constraint to the problem */
    13006 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &cardcons) );
    13007 ++(*nupgdconss);
    13008
    13009 /* delete oknapsack constraint */
    13010 SCIP_CALL( SCIPdelCons(scip, cons) );
    13011 ++(*ndelconss);
    13012
    13013 /* We need to disable the original knapsack constraint, since it might happen that the binary variables
    13014 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
    13015 * although the cardinality constraint is satisfied. */
    13016 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
    13017 assert( origcons != NULL );
    13018 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
    13019
    13020 for (v = 0; v < nvars; ++v)
    13021 {
    13022 int image;
    13023
    13024 assert ( SCIPhashmapExists(varhash, vars[v]) );
    13025 image = SCIPhashmapGetImageInt(varhash, vars[v]);
    13026 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
    13027 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
    13028 }
    13029 }
    13030 }
    13031 }
    13032 SCIPhashmapFree(&varhash);
    13033 SCIPfreeBufferArray(scip, &cardweights);
    13034 SCIPfreeBufferArray(scip, &cardvars);
    13035
    13036 if ( *nupgdconss > noldupgdconss )
    13037 success = TRUE;
    13038 }
    13039#endif
    13040
    13041 if( cutoff )
    13042 *result = SCIP_CUTOFF;
    13043 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
    13044 *result = SCIP_SUCCESS;
    13045 else
    13046 *result = SCIP_DIDNOTFIND;
    13047
    13048 return SCIP_OKAY;
    13049}
    13050
    13051/** propagation conflict resolving method of constraint handler */
    13052static
    13053SCIP_DECL_CONSRESPROP(consRespropKnapsack)
    13054{ /*lint --e{715}*/
    13055 SCIP_CONSDATA* consdata;
    13056 SCIP_Longint capsum;
    13057 int i;
    13058
    13059 assert(result != NULL);
    13060
    13061 consdata = SCIPconsGetData(cons);
    13062 assert(consdata != NULL);
    13063
    13064 /* check if we fixed a binary variable to one (due to negated clique) */
    13065 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
    13066 {
    13067 for( i = 0; i < consdata->nvars; ++i )
    13068 {
    13069 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
    13070 {
    13071 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
    13072 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
    13073 break;
    13074 }
    13075 }
    13076 assert(i < consdata->nvars);
    13077 }
    13078 else
    13079 {
    13080 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
    13081 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
    13082 * knapsack constraint, see one above call of SCIPinferBinvarCons
    13083 */
    13084 if( inferinfo < 0 )
    13085 capsum = 0;
    13086 else
    13087 {
    13088 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
    13089 * inferinfo stores the position of the inference variable (but maybe the variables were re-sorted)
    13090 */
    13091 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
    13092 capsum = consdata->weights[inferinfo];
    13093 else
    13094 {
    13095 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
    13096 {}
    13097 assert(i < consdata->nvars);
    13098 capsum = consdata->weights[i];
    13099 }
    13100 }
    13101
    13102 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
    13103 * the capacity
    13104 */
    13105 if( capsum <= consdata->capacity )
    13106 {
    13107 for( i = 0; i < consdata->nvars; i++ )
    13108 {
    13109 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
    13110 {
    13111 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
    13112 capsum += consdata->weights[i];
    13113 if( capsum > consdata->capacity )
    13114 break;
    13115 }
    13116 }
    13117 }
    13118 }
    13119
    13120 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
    13121 * to zero can included negated clique information. A negated clique means, that at most one of the clique
    13122 * variables can be zero. These information can be used to compute a minimum activity of the constraint and
    13123 * used to fix variables to zero.
    13124 *
    13125 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
    13126 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
    13127 * one.
    13128 */
    13129 *result = SCIP_SUCCESS;
    13130
    13131 return SCIP_OKAY;
    13132}
    13133
    13134/** variable rounding lock method of constraint handler */
    13135/**! [SnippetConsLockKnapsack] */
    13136static
    13137SCIP_DECL_CONSLOCK(consLockKnapsack)
    13138{ /*lint --e{715}*/
    13139 SCIP_CONSDATA* consdata;
    13140 int i;
    13141
    13142 consdata = SCIPconsGetData(cons);
    13143 assert(consdata != NULL);
    13144
    13145 for( i = 0; i < consdata->nvars; i++)
    13146 {
    13147 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
    13148 }
    13149
    13150 return SCIP_OKAY;
    13151}
    13152/**! [SnippetConsLockKnapsack] */
    13153
    13154/** constraint activation notification method of constraint handler */
    13155static
    13156SCIP_DECL_CONSACTIVE(consActiveKnapsack)
    13157{ /*lint --e{715}*/
    13159 {
    13160 SCIP_CALL( addNlrow(scip, cons) );
    13161 }
    13162
    13163 return SCIP_OKAY;
    13164}
    13165
    13166/** constraint deactivation notification method of constraint handler */
    13167static
    13168SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
    13169{ /*lint --e{715}*/
    13170 SCIP_CONSDATA* consdata;
    13171
    13172 assert(cons != NULL);
    13173
    13174 consdata = SCIPconsGetData(cons);
    13175 assert(consdata != NULL);
    13176
    13177 /* remove row from NLP, if still in solving
    13178 * if we are in exitsolve, the whole NLP will be freed anyway
    13179 */
    13180 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
    13181 {
    13182 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
    13183 }
    13184
    13185 return SCIP_OKAY;
    13186}
    13187
    13188/** variable deletion method of constraint handler */
    13189static
    13190SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
    13191{
    13192 assert(scip != NULL);
    13193 assert(conshdlr != NULL);
    13194 assert(conss != NULL || nconss == 0);
    13195
    13196 if( nconss > 0 )
    13197 {
    13198 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
    13199 }
    13200
    13201 return SCIP_OKAY;
    13202}
    13203
    13204/** constraint display method of constraint handler */
    13205static
    13206SCIP_DECL_CONSPRINT(consPrintKnapsack)
    13207{ /*lint --e{715}*/
    13208 SCIP_CONSDATA* consdata;
    13209 int i;
    13210
    13211 assert( scip != NULL );
    13212 assert( conshdlr != NULL );
    13213 assert( cons != NULL );
    13214
    13215 consdata = SCIPconsGetData(cons);
    13216 assert(consdata != NULL);
    13217
    13218 for( i = 0; i < consdata->nvars; ++i )
    13219 {
    13220 if( i > 0 )
    13221 SCIPinfoMessage(scip, file, " ");
    13222 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
    13223 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
    13224 }
    13225 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
    13226
    13227 return SCIP_OKAY;
    13228}
    13229
    13230/** constraint copying method of constraint handler */
    13231static
    13232SCIP_DECL_CONSCOPY(consCopyKnapsack)
    13233{ /*lint --e{715}*/
    13234 SCIP_VAR** sourcevars;
    13235 SCIP_Longint* weights;
    13236 SCIP_Real* coefs;
    13237 const char* consname;
    13238 int nvars;
    13239 int v;
    13240
    13241 /* get variables and coefficients of the source constraint */
    13242 sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
    13243 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
    13244 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
    13245
    13247 for( v = 0; v < nvars; ++v )
    13248 coefs[v] = (SCIP_Real) weights[v];
    13249
    13250 if( name != NULL )
    13251 consname = name;
    13252 else
    13253 consname = SCIPconsGetName(sourcecons);
    13254
    13255 /* copy the logic using the linear constraint copy method */
    13256 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
    13257 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
    13258 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
    13259 assert(cons != NULL);
    13260
    13261 SCIPfreeBufferArray(scip, &coefs);
    13262
    13263 return SCIP_OKAY;
    13264}
    13265
    13266/** constraint parsing method of constraint handler */
    13267static
    13268SCIP_DECL_CONSPARSE(consParseKnapsack)
    13269{ /*lint --e{715}*/
    13270 SCIP_VAR* var;
    13271 SCIP_Longint weight;
    13272 SCIP_VAR** vars;
    13273 SCIP_Longint* weights;
    13274 SCIP_Longint capacity;
    13275 char* endptr;
    13276 int nread;
    13277 int nvars;
    13278 int varssize;
    13279
    13280 assert(scip != NULL);
    13281 assert(success != NULL);
    13282 assert(str != NULL);
    13283 assert(name != NULL);
    13284 assert(cons != NULL);
    13285
    13286 *success = TRUE;
    13287
    13288 nvars = 0;
    13289 varssize = 5;
    13290 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
    13291 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
    13292
    13293 while( *str != '\0' )
    13294 {
    13295 /* try to parse coefficient, and use 1 if not successful */
    13296 weight = 1;
    13297 nread = 0;
    13298 (void) sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
    13299 str += nread;
    13300
    13301 /* parse variable name */
    13302 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
    13303
    13304 if( var == NULL )
    13305 {
    13306 endptr = strchr(endptr, '<');
    13307
    13308 if( endptr == NULL )
    13309 {
    13310 SCIPerrorMessage("no capacity found\n");
    13311 *success = FALSE;
    13312 }
    13313 else
    13314 str = endptr;
    13315
    13316 break;
    13317 }
    13318
    13319 str = endptr;
    13320
    13321 /* store weight and variable */
    13322 if( varssize <= nvars )
    13323 {
    13324 varssize = SCIPcalcMemGrowSize(scip, varssize+1);
    13325 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
    13326 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
    13327 }
    13328
    13329 vars[nvars] = var;
    13330 weights[nvars] = weight;
    13331 ++nvars;
    13332
    13333 /* skip whitespace */
    13334 SCIP_CALL( SCIPskipSpace((char**)&str) );
    13335 }
    13336
    13337 if( *success )
    13338 {
    13339 if( strncmp(str, "<=", 2) != 0 )
    13340 {
    13341 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
    13342 *success = FALSE;
    13343 }
    13344 else
    13345 {
    13346 str += 2;
    13347 }
    13348 }
    13349
    13350 if( *success )
    13351 {
    13352 /* skip whitespace */
    13353 SCIP_CALL( SCIPskipSpace((char**)&str) );
    13354
    13355 /* coverity[secure_coding] */
    13356 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
    13357 {
    13358 SCIPerrorMessage("error parsing capacity from '%s'\n", str);
    13359 *success = FALSE;
    13360 }
    13361 else
    13362 {
    13363 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
    13364 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    13365 }
    13366 }
    13367
    13368 SCIPfreeBufferArray(scip, &vars);
    13369 SCIPfreeBufferArray(scip, &weights);
    13370
    13371 return SCIP_OKAY;
    13372}
    13373
    13374/** constraint method of constraint handler which returns the variables (if possible) */
    13375static
    13376SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
    13377{ /*lint --e{715}*/
    13378 SCIP_CONSDATA* consdata;
    13379
    13380 consdata = SCIPconsGetData(cons);
    13381 assert(consdata != NULL);
    13382
    13383 if( varssize < consdata->nvars )
    13384 (*success) = FALSE;
    13385 else
    13386 {
    13387 assert(vars != NULL);
    13388
    13389 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
    13390 (*success) = TRUE;
    13391 }
    13392
    13393 return SCIP_OKAY;
    13394}
    13395
    13396/** constraint method of constraint handler which returns the number of variables (if possible) */
    13397static
    13398SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
    13399{ /*lint --e{715}*/
    13400 SCIP_CONSDATA* consdata;
    13401
    13402 consdata = SCIPconsGetData(cons);
    13403 assert(consdata != NULL);
    13404
    13405 (*nvars) = consdata->nvars;
    13406 (*success) = TRUE;
    13407
    13408 return SCIP_OKAY;
    13409}
    13410
    13411/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
    13412static
    13413SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
    13414{ /*lint --e{715}*/
    13415 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
    13416
    13417 return SCIP_OKAY;
    13418}
    13419
    13420/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
    13421static
    13422SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
    13423{ /*lint --e{715}*/
    13424 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
    13425
    13426 return SCIP_OKAY;
    13427}
    13428
    13429/*
    13430 * Event handler
    13431 */
    13432
    13433/** execution method of bound change event handler */
    13434static
    13435SCIP_DECL_EVENTEXEC(eventExecKnapsack)
    13436{ /*lint --e{715}*/
    13437 SCIP_CONSDATA* consdata;
    13438
    13439 assert(eventdata != NULL);
    13440 assert(eventdata->cons != NULL);
    13441
    13442 consdata = SCIPconsGetData(eventdata->cons);
    13443 assert(consdata != NULL);
    13444
    13445 switch( SCIPeventGetType(event) )
    13446 {
    13448 consdata->onesweightsum += eventdata->weight;
    13449 consdata->presolvedtiming = 0;
    13450 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
    13451 break;
    13453 consdata->onesweightsum -= eventdata->weight;
    13454 break;
    13456 consdata->presolvedtiming = 0;
    13457 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
    13458 break;
    13459 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
    13460 if( !consdata->existmultaggr )
    13461 {
    13462 SCIP_VAR* var;
    13463 var = SCIPeventGetVar(event);
    13464 assert(var != NULL);
    13465
    13466 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
    13468 {
    13469 consdata->existmultaggr = TRUE;
    13470 consdata->merged = FALSE;
    13471 }
    13474 consdata->merged = FALSE;
    13475 }
    13476 /*lint -fallthrough*/
    13477 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
    13478 consdata->presolvedtiming = 0;
    13479 break;
    13481 consdata->varsdeleted = TRUE;
    13482 break;
    13483 default:
    13484 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
    13485 return SCIP_INVALIDDATA;
    13486 }
    13487
    13488 return SCIP_OKAY;
    13489}
    13490
    13491
    13492/*
    13493 * constraint specific interface methods
    13494 */
    13495
    13496/** creates the handler for knapsack constraints and includes it in SCIP */
    13498 SCIP* scip /**< SCIP data structure */
    13499 )
    13500{
    13501 SCIP_EVENTHDLRDATA* eventhdlrdata;
    13502 SCIP_CONSHDLRDATA* conshdlrdata;
    13503 SCIP_CONSHDLR* conshdlr;
    13504
    13505 /* create knapsack constraint handler data */
    13506 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
    13507
    13508 /* include event handler for bound change events */
    13509 eventhdlrdata = NULL;
    13510 conshdlrdata->eventhdlr = NULL;
    13512 eventExecKnapsack, eventhdlrdata) );
    13513 conshdlrdata->probtoidxmap = NULL;
    13514 conshdlrdata->probtoidxmapsize = 0;
    13515
    13516 /* get event handler for bound change events */
    13517 if( conshdlrdata->eventhdlr == NULL )
    13518 {
    13519 SCIPerrorMessage("event handler for knapsack constraints not found\n");
    13520 return SCIP_PLUGINNOTFOUND;
    13521 }
    13522
    13523 /* include constraint handler */
    13526 consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
    13527 conshdlrdata) );
    13528
    13529 assert(conshdlr != NULL);
    13530
    13531 /* set non-fundamental callbacks via specific setter functions */
    13532 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
    13533 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
    13534 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
    13535 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
    13536 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
    13537 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
    13538 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
    13539 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
    13540 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
    13541 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
    13542 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
    13543 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
    13544 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
    13545 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
    13546 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
    13547 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
    13549 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
    13552 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
    13553 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
    13555 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
    13556 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
    13557 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) );
    13558 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) );
    13559
    13560 if( SCIPfindConshdlr(scip,"linear") != NULL )
    13561 {
    13562 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
    13564 }
    13565
    13566 /* add knapsack constraint handler parameters */
    13568 "constraints/" CONSHDLR_NAME "/sepacardfreq",
    13569 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
    13570 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
    13572 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
    13573 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
    13574 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
    13576 "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
    13577 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
    13578 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
    13580 "constraints/" CONSHDLR_NAME "/maxrounds",
    13581 "maximal number of separation rounds per node (-1: unlimited)",
    13582 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
    13584 "constraints/" CONSHDLR_NAME "/maxroundsroot",
    13585 "maximal number of separation rounds per node in the root node (-1: unlimited)",
    13586 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
    13588 "constraints/" CONSHDLR_NAME "/maxsepacuts",
    13589 "maximal number of cuts separated per separation round",
    13590 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
    13592 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
    13593 "maximal number of cuts separated per separation round in the root node",
    13594 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
    13596 "constraints/" CONSHDLR_NAME "/disaggregation",
    13597 "should disaggregation of knapsack constraints be allowed in preprocessing?",
    13598 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
    13600 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
    13601 "should presolving try to simplify knapsacks",
    13602 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
    13604 "constraints/" CONSHDLR_NAME "/negatedclique",
    13605 "should negated clique information be used in solving process",
    13606 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
    13608 "constraints/" CONSHDLR_NAME "/presolpairwise",
    13609 "should pairwise constraint comparison be performed in presolving?",
    13610 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
    13612 "constraints/" CONSHDLR_NAME "/presolusehashing",
    13613 "should hash table be used for detecting redundant constraints in advance",
    13614 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
    13616 "constraints/" CONSHDLR_NAME "/dualpresolving",
    13617 "should dual presolving steps be performed?",
    13618 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
    13620 "constraints/" CONSHDLR_NAME "/usegubs",
    13621 "should GUB information be used for separation?",
    13622 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
    13624 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
    13625 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
    13626 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
    13628 "constraints/" CONSHDLR_NAME "/detectlowerbound",
    13629 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
    13630 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
    13632 "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
    13633 "should clique partition information be updated when old partition seems outdated?",
    13634 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
    13636 "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
    13637 "factor on the growth of global cliques to decide when to update a previous "
    13638 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
    13639 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
    13640#ifdef WITH_CARDINALITY_UPGRADE
    13642 "constraints/" CONSHDLR_NAME "/upgdcardinality",
    13643 "if TRUE then try to update knapsack constraints to cardinality constraints",
    13644 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
    13645#endif
    13646 return SCIP_OKAY;
    13647}
    13648
    13649/** creates and captures a knapsack constraint
    13650 *
    13651 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13652 */
    13653/**! [SnippetConsCreationKnapsack] */
    13655 SCIP* scip, /**< SCIP data structure */
    13656 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13657 const char* name, /**< name of constraint */
    13658 int nvars, /**< number of items in the knapsack */
    13659 SCIP_VAR** vars, /**< array with item variables */
    13660 SCIP_Longint* weights, /**< array with item weights */
    13661 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
    13662 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    13663 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    13664 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    13665 * Usually set to TRUE. */
    13666 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    13667 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    13668 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    13669 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    13670 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    13671 * Usually set to TRUE. */
    13672 SCIP_Bool local, /**< is constraint only valid locally?
    13673 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    13674 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    13675 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    13676 * adds coefficients to this constraint. */
    13677 SCIP_Bool dynamic, /**< is constraint subject to aging?
    13678 * Usually set to FALSE. Set to TRUE for own cuts which
    13679 * are separated as constraints. */
    13680 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    13681 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    13682 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    13683 * if it may be moved to a more global node?
    13684 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    13685 )
    13686{
    13687 SCIP_CONSHDLRDATA* conshdlrdata;
    13688 SCIP_CONSHDLR* conshdlr;
    13689 SCIP_CONSDATA* consdata;
    13690 int i;
    13691
    13692 /* find the knapsack constraint handler */
    13693 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    13694 if( conshdlr == NULL )
    13695 {
    13696 SCIPerrorMessage("knapsack constraint handler not found\n");
    13697 return SCIP_PLUGINNOTFOUND;
    13698 }
    13699
    13700 /* check whether all variables are binary */
    13701 assert(vars != NULL || nvars == 0);
    13702 for( i = 0; i < nvars; ++i )
    13703 {
    13704 if( !SCIPvarIsBinary(vars[i]) )
    13705 {
    13706 SCIPerrorMessage("item <%s> is not binary\n", SCIPvarGetName(vars[i]));
    13707 return SCIP_INVALIDDATA;
    13708 }
    13709 }
    13710
    13711 /* get event handler */
    13712 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13713 assert(conshdlrdata != NULL);
    13714 assert(conshdlrdata->eventhdlr != NULL);
    13715
    13716 /* create constraint data */
    13717 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
    13718
    13719 /* create constraint */
    13720 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    13721 local, modifiable, dynamic, removable, stickingatnode) );
    13722
    13723 /* catch events for variables */
    13724 if( SCIPisTransformed(scip) )
    13725 {
    13726 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
    13727 }
    13728
    13729 return SCIP_OKAY;
    13730}
    13731/**! [SnippetConsCreationKnapsack] */
    13732
    13733/** creates and captures a knapsack constraint
    13734 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
    13735 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
    13736 *
    13737 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
    13738 *
    13739 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13740 */
    13742 SCIP* scip, /**< SCIP data structure */
    13743 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13744 const char* name, /**< name of constraint */
    13745 int nvars, /**< number of items in the knapsack */
    13746 SCIP_VAR** vars, /**< array with item variables */
    13747 SCIP_Longint* weights, /**< array with item weights */
    13748 SCIP_Longint capacity /**< capacity of knapsack */
    13749 )
    13750{
    13751 assert(scip != NULL);
    13752
    13753 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
    13755
    13756 return SCIP_OKAY;
    13757}
    13758
    13759/** adds new item to knapsack constraint */
    13761 SCIP* scip, /**< SCIP data structure */
    13762 SCIP_CONS* cons, /**< constraint data */
    13763 SCIP_VAR* var, /**< item variable */
    13764 SCIP_Longint weight /**< item weight */
    13765 )
    13766{
    13767 assert(var != NULL);
    13768 assert(scip != NULL);
    13769
    13770 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13771 {
    13772 SCIPerrorMessage("constraint is not a knapsack constraint\n");
    13773 return SCIP_INVALIDDATA;
    13774 }
    13775
    13776 SCIP_CALL( addCoef(scip, cons, var, weight) );
    13777
    13778 return SCIP_OKAY;
    13779}
    13780
    13781/** gets the capacity of the knapsack constraint */
    13783 SCIP* scip, /**< SCIP data structure */
    13784 SCIP_CONS* cons /**< constraint data */
    13785 )
    13786{
    13787 SCIP_CONSDATA* consdata;
    13788
    13789 assert(scip != NULL);
    13790
    13791 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13792 {
    13793 SCIPerrorMessage("constraint is not a knapsack constraint\n");
    13794 SCIPABORT();
    13795 return 0; /*lint !e527*/
    13796 }
    13797
    13798 consdata = SCIPconsGetData(cons);
    13799 assert(consdata != NULL);
    13800
    13801 return consdata->capacity;
    13802}
    13803
    13804/** changes capacity of the knapsack constraint
    13805 *
    13806 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
    13807 */
    13809 SCIP* scip, /**< SCIP data structure */
    13810 SCIP_CONS* cons, /**< constraint data */
    13811 SCIP_Longint capacity /**< new capacity of knapsack */
    13812 )
    13813{
    13814 SCIP_CONSDATA* consdata;
    13815
    13816 assert(scip != NULL);
    13817
    13818 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13819 {
    13820 SCIPerrorMessage("constraint is not a knapsack constraint\n");
    13821 return SCIP_INVALIDDATA;
    13822 }
    13823
    13825 {
    13826 SCIPerrorMessage("method can only be called during problem creation stage\n");
    13827 return SCIP_INVALIDDATA;
    13828 }
    13829
    13830 consdata = SCIPconsGetData(cons);
    13831 assert(consdata != NULL);
    13832
    13833 consdata->capacity = capacity;
    13834
    13835 return SCIP_OKAY;
    13836}
    13837
    13838/** gets the number of items in the knapsack constraint */
    13840 SCIP* scip, /**< SCIP data structure */
    13841 SCIP_CONS* cons /**< constraint data */
    13842 )
    13843{
    13844 SCIP_CONSDATA* consdata;
    13845
    13846 assert(scip != NULL);
    13847
    13848 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13849 {
    13850 SCIPerrorMessage("constraint is not a knapsack constraint\n");
    13851 SCIPABORT();
    13852 return -1; /*lint !e527*/
    13853 }
    13854
    13855 consdata = SCIPconsGetData(cons);
    13856 assert(consdata != NULL);
    13857
    13858 return consdata->nvars;
    13859}
    13860
    13861/** gets the array of variables in the knapsack constraint; the user must not modify this array! */
    13863 SCIP* scip, /**< SCIP data structure */
    13864 SCIP_CONS* cons /**< constraint data */
    13865 )
    13866{
    13867 SCIP_CONSDATA* consdata;
    13868
    13869 assert(scip != NULL);
    13870
    13871 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13872 {
    13873 SCIPerrorMessage("constraint is not a knapsack constraint\n");
    13874 SCIPABORT();
    13875 return NULL; /*lint !e527*/
    13876 }
    13877
    13878 consdata = SCIPconsGetData(cons);
    13879 assert(consdata != NULL);
    13880
    13881 return consdata->vars;
    13882}
    13883
    13884/** gets the array of weights in the knapsack constraint; the user must not modify this array! */
    13886 SCIP* scip, /**< SCIP data structure */
    13887 SCIP_CONS* cons /**< constraint data */
    13888 )
    13889{
    13890 SCIP_CONSDATA* consdata;
    13891
    13892 assert(scip != NULL);
    13893
    13894 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13895 {
    13896 SCIPerrorMessage("constraint is not a knapsack constraint\n");
    13897 SCIPABORT();
    13898 return NULL; /*lint !e527*/
    13899 }
    13900
    13901 consdata = SCIPconsGetData(cons);
    13902 assert(consdata != NULL);
    13903
    13904 return consdata->weights;
    13905}
    13906
    13907/** gets the dual solution of the knapsack constraint in the current LP */
    13909 SCIP* scip, /**< SCIP data structure */
    13910 SCIP_CONS* cons /**< constraint data */
    13911 )
    13912{
    13913 SCIP_CONSDATA* consdata;
    13914
    13915 assert(scip != NULL);
    13916
    13917 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13918 {
    13919 SCIPerrorMessage("constraint is not a knapsack constraint\n");
    13920 SCIPABORT();
    13921 return SCIP_INVALID; /*lint !e527*/
    13922 }
    13923
    13924 consdata = SCIPconsGetData(cons);
    13925 assert(consdata != NULL);
    13926
    13927 if( consdata->row != NULL )
    13928 return SCIProwGetDualsol(consdata->row);
    13929 else
    13930 return 0.0;
    13931}
    13932
    13933/** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
    13935 SCIP* scip, /**< SCIP data structure */
    13936 SCIP_CONS* cons /**< constraint data */
    13937 )
    13938{
    13939 SCIP_CONSDATA* consdata;
    13940
    13941 assert(scip != NULL);
    13942
    13943 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13944 {
    13945 SCIPerrorMessage("constraint is not a knapsack constraint\n");
    13946 SCIPABORT();
    13947 return SCIP_INVALID; /*lint !e527*/
    13948 }
    13949
    13950 consdata = SCIPconsGetData(cons);
    13951 assert(consdata != NULL);
    13952
    13953 if( consdata->row != NULL )
    13954 return SCIProwGetDualfarkas(consdata->row);
    13955 else
    13956 return 0.0;
    13957}
    13958
    13959/** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
    13960 * the user must not modify the row!
    13961 */
    13963 SCIP* scip, /**< SCIP data structure */
    13964 SCIP_CONS* cons /**< constraint data */
    13965 )
    13966{
    13967 SCIP_CONSDATA* consdata;
    13968
    13969 assert(scip != NULL);
    13970
    13971 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13972 {
    13973 SCIPerrorMessage("constraint is not a knapsack\n");
    13974 SCIPABORT();
    13975 return NULL; /*lint !e527*/
    13976 }
    13977
    13978 consdata = SCIPconsGetData(cons);
    13979 assert(consdata != NULL);
    13980
    13981 return consdata->row;
    13982}
    13983
    13984/** creates and returns the row of the given knapsack constraint */
    13986 SCIP* scip, /**< SCIP data structure */
    13987 SCIP_CONS* cons /**< constraint data */
    13988 )
    13989{
    13990 SCIP_CONSDATA* consdata;
    13991 int i;
    13992
    13993 assert(scip != NULL);
    13994
    13995 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
    13996 {
    13997 SCIPerrorMessage("constraint is not a knapsack\n");
    13998 SCIPABORT();
    13999 return SCIP_ERROR; /*lint !e527*/
    14000 }
    14001
    14002 consdata = SCIPconsGetData(cons);
    14003 assert(consdata != NULL);
    14004 assert(consdata->row == NULL);
    14005
    14006 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
    14007 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
    14009
    14010 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
    14011 for( i = 0; i < consdata->nvars; ++i )
    14012 {
    14013 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
    14014 }
    14015 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
    14016
    14017 return SCIP_OKAY;
    14018}
    14019
    14020/** cleans up (multi-)aggregations and fixings from knapsack constraints */
    14022 SCIP* scip, /**< SCIP data structure */
    14023 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
    14024 SCIP_Bool* infeasible, /**< pointer to return whether the problem was detected to be infeasible */
    14025 int* ndelconss /**< pointer to count number of deleted constraints */
    14026 )
    14027{
    14028 SCIP_CONSHDLR* conshdlr;
    14029 SCIP_CONS** conss;
    14030 int nconss;
    14031 int i;
    14032
    14033 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    14034 if( conshdlr == NULL )
    14035 return SCIP_OKAY;
    14036
    14037 assert(infeasible != NULL);
    14038 *infeasible = FALSE;
    14039
    14040 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
    14041 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
    14042
    14043 /* loop backwards since then deleted constraints do not interfere with the loop */
    14044 for( i = nconss - 1; i >= 0; --i )
    14045 {
    14046 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
    14047
    14048 if( *infeasible )
    14049 break;
    14050
    14051 if( SCIPconsGetData(conss[i])->nvars >= 1 )
    14052 continue;
    14053
    14054 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
    14055 ++(*ndelconss);
    14056 }
    14057
    14058 return SCIP_OKAY;
    14059}
    SCIP_VAR * h
    Definition: circlepacking.c:68
    SCIP_VAR * w
    Definition: circlepacking.c:67
    SCIP_VAR ** b
    Definition: circlepacking.c:65
    constraint handler for cardinality constraints
    static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
    static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
    static SCIP_DECL_CONSCOPY(consCopyKnapsack)
    static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
    static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
    static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
    GUBConsstatus
    @ GUBCONSSTATUS_BELONGSTOSET_GF
    @ GUBCONSSTATUS_UNINITIAL
    @ GUBCONSSTATUS_BELONGSTOSET_GR
    @ GUBCONSSTATUS_BELONGSTOSET_GOC1
    @ GUBCONSSTATUS_BELONGSTOSET_GNC1
    @ GUBCONSSTATUS_BELONGSTOSET_GC2
    #define DEFAULT_DUALPRESOLVING
    static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
    #define CONSHDLR_NEEDSCONS
    Definition: cons_knapsack.c:93
    #define DEFAULT_SEPACARDFREQ
    #define CONSHDLR_SEPAFREQ
    Definition: cons_knapsack.c:86
    static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
    static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
    #define KNAPSACKRELAX_MAXDELTA
    static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
    static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
    static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
    static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
    #define DEFAULT_USEGUBS
    #define CONSHDLR_CHECKPRIORITY
    Definition: cons_knapsack.c:85
    static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
    #define CONSHDLR_DESC
    Definition: cons_knapsack.c:82
    static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
    static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
    static SCIP_DECL_CONSEXIT(consExitKnapsack)
    static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
    static SCIP_DECL_CONSPRINT(consPrintKnapsack)
    #define KNAPSACKRELAX_MAXSCALE
    static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
    static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
    #define DEFAULT_DETECTCUTOFFBOUND
    static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
    static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
    static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
    static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
    static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
    #define CONSHDLR_PROP_TIMING
    Definition: cons_knapsack.c:96
    static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
    static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
    static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
    static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
    static SCIP_DECL_CONSTRANS(consTransKnapsack)
    static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
    static SCIP_DECL_CONSPROP(consPropKnapsack)
    static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
    static SCIP_DECL_CONSRESPROP(consRespropKnapsack)
    static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
    static SCIP_RETCODE createNormalizedKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, 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)
    #define CONSHDLR_MAXPREROUNDS
    Definition: cons_knapsack.c:90
    static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
    static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
    #define DEFAULT_PRESOLPAIRWISE
    static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
    #define CONSHDLR_SEPAPRIORITY
    Definition: cons_knapsack.c:83
    static SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
    #define DEFAULT_MAXROUNDSROOT
    struct sortkeypair SORTKEYPAIR
    #define DEFAULT_NEGATEDCLIQUE
    enum GUBVarstatus GUBVARSTATUS
    static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
    #define DEFAULT_MAXCARDBOUNDDIST
    static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
    #define MAXCOVERSIZEITERLEWI
    static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
    static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
    static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
    static SCIP_DECL_CONSCHECK(consCheckKnapsack)
    static void sortItems(SCIP_CONSDATA *consdata)
    static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
    static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
    static SCIP_DECL_CONSINIT(consInitKnapsack)
    static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
    static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
    static SCIP_DECL_EVENTEXEC(eventExecKnapsack)
    static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
    static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
    static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
    static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
    static SCIP_DECL_CONSINITLP(consInitlpKnapsack)
    static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
    #define HASHSIZE_KNAPSACKCONS
    static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
    #define DEFAULT_MAXSEPACUTSROOT
    static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
    static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
    static SCIP_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
    static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
    #define DEFAULT_PRESOLUSEHASHING
    #define MAX_CLIQUELENGTH
    static SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
    #define DEFAULT_CLQPARTUPDATEFAC
    static SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
    static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
    static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
    static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
    #define IDX(j, d)
    static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
    static SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
    static SCIP_RETCODE sequentialUpAndDownLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *varsM1, int *varsM2, int *varsF, int *varsR, int nvarsM1, int nvarsM2, int nvarsF, int nvarsR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs)
    static SCIP_RETCODE separateSequLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_SOL *sol, SCIP_GUBSET *gubset, SCIP_Bool *cutoff, int *ncuts)
    #define GUBCONSGROWVALUE
    static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
    static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
    #define MINGAINPERNMINCOMPARISONS
    static SCIP_RETCODE greedyCliqueAlgorithm(SCIP *const scip, SCIP_VAR **items, SCIP_Longint *weights, int nitems, SCIP_Longint capacity, SCIP_Bool sorteditems, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
    #define DEFAULT_CLIQUEEXTRACTFACTOR
    #define DEFAULT_SIMPLIFYINEQUALITIES
    static SCIP_RETCODE eventdataFree(SCIP *scip, SCIP_EVENTDATA **eventdata)
    static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
    static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
    static SCIP_RETCODE getLiftingSequence(SCIP *scip, SCIP_Real *solvals, SCIP_Longint *weights, int *varsF, int *varsC2, int *varsR, int nvarsF, int nvarsC2, int nvarsR)
    #define CONSHDLR_PROPFREQ
    Definition: cons_knapsack.c:87
    #define MAXNCLIQUEVARSCOMP
    static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
    static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
    static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
    static SCIP_DECL_CONSACTIVE(consActiveKnapsack)
    #define NMINCOMPARISONS
    static SCIP_RETCODE simplifyInequalities(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss, SCIP_Bool *cutoff)
    enum GUBConsstatus GUBCONSSTATUS
    static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
    static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
    #define CONSHDLR_PRESOLTIMING
    Definition: cons_knapsack.c:95
    static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
    #define DEFAULT_MAXSEPACUTS
    static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
    static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
    static SCIP_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
    static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
    static SCIP_DECL_CONSFREE(consFreeKnapsack)
    static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
    static SCIP_RETCODE tightenWeights(SCIP *scip, SCIP_CONS *cons, SCIP_PRESOLTIMING presoltiming, int *nchgcoefs, int *nchgsides, int *naddconss, int *ndelconss, SCIP_Bool *cutoff)
    #define CONSHDLR_EAGERFREQ
    Definition: cons_knapsack.c:88
    static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
    static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
    #define EVENTHDLR_DESC
    Definition: cons_knapsack.c:99
    #define KNAPSACKRELAX_MAXDNOM
    #define USESUPADDLIFT
    #define DEFAULT_MAXROUNDS
    static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
    static SCIP_DECL_CONSLOCK(consLockKnapsack)
    #define CONSHDLR_ENFOPRIORITY
    Definition: cons_knapsack.c:84
    #define MAXABSVBCOEF
    static SCIP_DECL_CONSPARSE(consParseKnapsack)
    #define LINCONSUPGD_PRIORITY
    #define CONSHDLR_DELAYSEPA
    Definition: cons_knapsack.c:91
    #define MAX_USECLIQUES_SIZE
    #define DEFAULT_UPDATECLIQUEPARTITIONS
    GUBVarstatus
    @ GUBVARSTATUS_BELONGSTOSET_F
    @ GUBVARSTATUS_BELONGSTOSET_C1
    @ GUBVARSTATUS_BELONGSTOSET_R
    @ GUBVARSTATUS_BELONGSTOSET_C2
    @ GUBVARSTATUS_CAPACITYEXCEEDED
    @ GUBVARSTATUS_UNINITIAL
    static SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
    #define CONSHDLR_NAME
    Definition: cons_knapsack.c:81
    #define EVENTHDLR_NAME
    Definition: cons_knapsack.c:98
    static SCIP_DECL_CONSDELETE(consDeleteKnapsack)
    static SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
    static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
    static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
    static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
    static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
    #define DEFAULT_DISAGGREGATION
    static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
    static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
    #define DEFAULT_DETECTLOWERBOUND
    static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
    static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
    #define CONSHDLR_DELAYPROP
    Definition: cons_knapsack.c:92
    static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
    #define EVENTTYPE_KNAPSACK
    #define MAX_ZEROITEMS_SIZE
    Constraint handler for knapsack constraints of the form , x binary and .
    Constraint handler for linear constraints in their most general form, .
    Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
    Constraint handler for the set partitioning / packing / covering constraints .
    #define NULL
    Definition: def.h:255
    #define SCIP_MAXSTRLEN
    Definition: def.h:276
    #define SCIP_Longint
    Definition: def.h:148
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:304
    #define SCIP_INVALID
    Definition: def.h:185
    #define SCIP_Bool
    Definition: def.h:98
    #define MIN(x, y)
    Definition: def.h:231
    #define SCIP_Real
    Definition: def.h:163
    #define TRUE
    Definition: def.h:100
    #define FALSE
    Definition: def.h:101
    #define MAX(x, y)
    Definition: def.h:227
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:155
    #define SCIPABORT()
    Definition: def.h:334
    #define REALABS(x)
    Definition: def.h:189
    #define SCIP_LONGINT_MAX
    Definition: def.h:149
    #define SCIP_CALL(x)
    Definition: def.h:362
    SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
    int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateRowKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
    SCIP_RETCODE SCIPsolveKnapsackApproximately(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_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible, int *ndelconss)
    SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
    SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, 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: cons_setppc.c:9460
    SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
    SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
    SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
    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 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)
    SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, 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_Bool global, SCIP_Bool *valid)
    SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, 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 SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
    SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
    Definition: scip_copy.c:662
    SCIP_Bool SCIPisTransformed(SCIP *scip)
    Definition: scip_general.c:647
    SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
    Definition: scip_general.c:668
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    int SCIPgetNObjVars(SCIP *scip)
    Definition: scip_prob.c:2616
    SCIP_RETCODE SCIPaddConsUpgrade(SCIP *scip, SCIP_CONS *oldcons, SCIP_CONS **newcons)
    Definition: scip_prob.c:3368
    int SCIPgetNContVars(SCIP *scip)
    Definition: scip_prob.c:2569
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
    Definition: scip_prob.c:3476
    SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3420
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    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 SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3400
    void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
    Definition: misc.c:2348
    #define SCIPhashSix(a, b, c, d, e, f)
    Definition: pub_misc.h:580
    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
    void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
    Definition: misc.c:2596
    SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2665
    SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2535
    SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
    Definition: scip_prob.c:4289
    SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:4067
    SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
    Definition: scip_prob.c:4178
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    #define SCIPdebugMsgPrint
    Definition: scip_message.h:79
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
    Definition: misc.c:9197
    SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
    Definition: misc.c:9641
    SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
    Definition: misc.c:11162
    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 SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    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
    int SCIPgetNLPBranchCands(SCIP *scip)
    Definition: scip_branch.c:436
    SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
    SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
    SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
    SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
    int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4802
    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_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4759
    SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
    Definition: scip_cons.c:540
    SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
    Definition: scip_cons.c:396
    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 SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
    Definition: scip_cons.c:693
    SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:5046
    SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)))
    Definition: scip_cons.c:900
    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 SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
    Definition: scip_cons.c:420
    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 SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)))
    Definition: scip_cons.c:924
    SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
    Definition: scip_cons.c:468
    SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
    Definition: scip_cons.c:762
    SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
    Definition: scip_cons.c:624
    SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
    Definition: scip_cons.c:444
    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
    int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4816
    SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
    Definition: scip_cons.c:854
    int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:5276
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4739
    SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSACTIVE((*consactive)))
    Definition: scip_cons.c:670
    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
    int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
    Definition: cons.c:8845
    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_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:2042
    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_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:2014
    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_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
    Definition: scip_cons.c:1371
    SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
    Definition: scip_cons.c:1346
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8572
    SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_cons.c:1784
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8662
    SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:117
    SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
    Definition: scip_cut.c:135
    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
    SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
    Definition: event.c:1194
    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_VAR * SCIPeventGetVar(SCIP_EVENT *event)
    Definition: event.c:1217
    #define SCIPfreeBuffer(scip, ptr)
    Definition: scip_mem.h:134
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocClearBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:97
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    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 SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
    Definition: scip_nlp.c:424
    SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
    Definition: scip_nlp.c:396
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
    Definition: scip_nlp.c:1058
    SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
    Definition: nlp.c:1953
    SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
    Definition: scip_nlp.c:954
    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 SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1367
    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_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1429
    SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1458
    SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
    Definition: lp.c:17719
    SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
    Definition: lp.c:17917
    SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
    Definition: lp.c:17706
    const char * SCIPsepaGetName(SCIP_SEPA *sepa)
    Definition: sepa.c:746
    SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
    Definition: sepa.c:913
    SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_sol.c:1846
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
    Definition: scip_sol.c:469
    SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
    int SCIPgetNSepaRounds(SCIP *scip)
    SCIP_Real SCIPgetLowerbound(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    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 SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPepsilon(SCIP *scip)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPinRepropagation(SCIP *scip)
    Definition: scip_tree.c:146
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    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:24483
    SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
    Definition: var.c:23535
    SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
    Definition: scip_var.c:5210
    SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
    Definition: var.c:23844
    SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
    Definition: var.c:23869
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24505
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23643
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23479
    SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
    Definition: scip_var.c:8882
    SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
    Definition: scip_var.c:2119
    int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24569
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23387
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4386
    SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *scip, SCIP_VAR **vars, int nvars, int **probtoidxmap, int *probtoidxmapsize, int *cliquepartition, int *ncliques)
    Definition: scip_var.c:9410
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24269
    SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
    Definition: var.c:23431
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23901
    SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
    Definition: var.c:17551
    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_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24143
    SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24586
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23653
    SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
    Definition: scip_var.c:5118
    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:23663
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23268
    SCIP_RETCODE SCIPcalcCliquePartition(SCIP *scip, SCIP_VAR **vars, int nvars, int **probtoidxmap, int *probtoidxmapsize, int *cliquepartition, int *ncliques)
    Definition: scip_var.c:9330
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
    Definition: var.c:24515
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24525
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23491
    SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24615
    SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:2332
    SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
    Definition: scip_var.c:2166
    SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
    Definition: var.c:23807
    int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
    Definition: var.c:23795
    int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24643
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24235
    SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
    Definition: var.c:23444
    int SCIPgetNCliques(SCIP *scip)
    Definition: scip_var.c:9512
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24495
    SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24654
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24121
    SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
    Definition: scip_var.c:10318
    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:17275
    SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
    Definition: var.c:17643
    SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:7412
    SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
    Definition: var.c:24557
    SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
    Definition: scip_var.c:361
    SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
    Definition: scip_var.c:2236
    SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
    Definition: var.c:24537
    SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
    Definition: var.c:16808
    SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
    Definition: var.c:24547
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4328
    SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
    Definition: scip_var.c:2199
    SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24601
    SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:1853
    SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
    Definition: scip_var.c:10984
    SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
    Definition: var.c:17611
    SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
    Definition: var.c:23819
    void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
    void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
    void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
    void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
    void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
    void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
    void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
    void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    SCIP_RETCODE SCIPskipSpace(char **s)
    Definition: misc.c:10816
    SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
    SCIP_RETCODE SCIPextendPermsymDetectionGraphLinear(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool *success)
    SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
    Definition: implics.c:3384
    int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
    Definition: implics.c:3374
    SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
    Definition: implics.c:3396
    memory allocation routines
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    struct BMS_BlkMem BMS_BLKMEM
    Definition: memory.h:437
    INLINE Rational & min(Rational &r1, Rational &r2)
    public methods for managing constraints
    public methods for managing events
    public methods for implications, variable bounds, and cliques
    public methods for LP management
    public methods for message output
    #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 SCIPdebugMessage
    Definition: pub_message.h:96
    #define SCIPdebugPrintf
    Definition: pub_message.h:99
    public data structures and miscellaneous methods
    methods for selecting (weighted) k-medians
    methods for sorting joint arrays of various types
    public methods for separators
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for conflict handler plugins and conflict analysis
    public methods for constraint handler plugins and constraints
    public methods for problem copies
    public methods for cuts and aggregation rows
    public methods for event handler plugins and event handlers
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for nonlinear relaxation
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for the probing mode
    public methods for solutions
    public methods for querying solving statistics
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
    Main separation function.
    Definition: sepa_flower.c:1221
    GUBVARSTATUS * gubvarsstatus
    GUBCONSSTATUS * gubconsstatus
    int * gubvarsidx
    int * gubconssidx
    SCIP_GUBCONS ** gubconss
    structs for symmetry computations
    methods for dealing with symmetry detection graphs
    @ SCIP_CONFTYPE_PROPAGATION
    Definition: type_conflict.h:62
    struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
    Definition: type_cons.h:64
    struct SCIP_ConsData SCIP_CONSDATA
    Definition: type_cons.h:65
    struct SCIP_EventData SCIP_EVENTDATA
    Definition: type_event.h:179
    #define SCIP_EVENTTYPE_UBTIGHTENED
    Definition: type_event.h:79
    #define SCIP_EVENTTYPE_VARFIXED
    Definition: type_event.h:72
    #define SCIP_EVENTTYPE_VARDELETED
    Definition: type_event.h:71
    struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
    Definition: type_event.h:160
    #define SCIP_EVENTTYPE_LBRELAXED
    Definition: type_event.h:78
    #define SCIP_EVENTTYPE_FORMAT
    Definition: type_event.h:157
    #define SCIP_EVENTTYPE_IMPLADDED
    Definition: type_event.h:85
    #define SCIP_EVENTTYPE_LBTIGHTENED
    Definition: type_event.h:77
    @ SCIP_EXPRCURV_LINEAR
    Definition: type_expr.h:65
    @ SCIP_BOUNDTYPE_UPPER
    Definition: type_lp.h:58
    enum SCIP_BoundType SCIP_BOUNDTYPE
    Definition: type_lp.h:60
    @ 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_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_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_PLUGINNOTFOUND
    Definition: type_retcode.h:54
    @ SCIP_NOMEMORY
    Definition: type_retcode.h:44
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_PROBLEM
    Definition: type_set.h:45
    @ SCIP_STAGE_INITSOLVE
    Definition: type_set.h:52
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53
    @ SCIP_STAGE_TRANSFORMING
    Definition: type_set.h:46
    enum SYM_Symtype SYM_SYMTYPE
    Definition: type_symmetry.h:64
    @ SYM_SYMTYPE_SIGNPERM
    Definition: type_symmetry.h:62
    @ SYM_SYMTYPE_PERM
    Definition: type_symmetry.h:61
    #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_VARSTATUS_FIXED
    Definition: type_var.h:54
    @ SCIP_VARSTATUS_MULTAGGR
    Definition: type_var.h:56
    @ SCIP_VARSTATUS_NEGATED
    Definition: type_var.h:57
    @ SCIP_VARSTATUS_AGGREGATED
    Definition: type_var.h:55
    @ SCIP_LOCKTYPE_MODEL
    Definition: type_var.h:141