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
    75#ifdef WITH_CARDINALITY_UPGRADE
    77#endif
    78
    79/* constraint handler properties */
    80#define CONSHDLR_NAME "knapsack"
    81#define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
    82#define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
    83#define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
    84#define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
    85#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
    86#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
    87#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
    88 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
    89#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
    90#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
    91#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
    92#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
    93
    94#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
    95#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
    96
    97#define EVENTHDLR_NAME "knapsack"
    98#define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
    99#define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
    100 | SCIP_EVENTTYPE_UBTIGHTENED \
    101 | SCIP_EVENTTYPE_VARFIXED \
    102 | SCIP_EVENTTYPE_VARDELETED \
    103 | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
    104
    105#define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
    106
    107#define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
    108#define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
    109
    110#define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
    111#define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
    112#define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
    113
    114#define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
    115#define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
    116#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
    117#define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
    118#define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
    119#define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
    120 * to best node's dual bound for separating knapsack cuts */
    121#define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
    122#define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
    123#define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
    124
    125#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
    126#define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
    127
    128#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
    129#define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
    130
    131#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
    132#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
    133#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
    134 * comparison round */
    135#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
    136#define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
    137 * function defining an upper bound and prevent these constraints from
    138 * entering the LP */
    139#define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
    140 * function defining a lower bound and prevent these constraints from
    141 * entering the LP */
    142#define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
    143#define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
    144
    145#define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
    146#define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
    147#define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
    148#define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
    149 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
    150#define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
    151#define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
    152#ifdef WITH_CARDINALITY_UPGRADE
    153#define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
    154#endif
    155#define DEFAULT_COPYTYPEDCONS FALSE /**< should knapsack constraints be copied as knapsack instead of linear? */
    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 SCIP_Bool copytypedcons; /**< should knapsack constraints be copied as knapsack instead of linear? */
    225};
    226
    227
    228/** constraint data for knapsack constraints */
    229struct SCIP_ConsData
    230{
    231 SCIP_VAR** vars; /**< variables in knapsack constraint */
    232 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
    233 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
    234 int* cliquepartition; /**< clique indices of the clique partition */
    235 int* negcliquepartition; /**< clique indices of the negated clique partition */
    236 SCIP_ROW* row; /**< corresponding LP row */
    237 SCIP_NLROW* nlrow; /**< corresponding NLP row */
    238 int nvars; /**< number of variables in knapsack constraint */
    239 int varssize; /**< size of vars, weights, and eventdata arrays */
    240 int ncliques; /**< number of cliques in the clique partition */
    241 int nnegcliques; /**< number of cliques in the negated clique partition */
    242 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
    243 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
    244 SCIP_Longint capacity; /**< capacity of knapsack */
    245 SCIP_Longint weightsum; /**< sum of all weights */
    246 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
    247 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
    248 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
    249 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
    250 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
    251 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
    252 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
    253 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
    254 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
    255};
    256
    257/** event data for bound changes events */
    258struct SCIP_EventData
    259{
    260 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
    261 SCIP_Longint weight; /**< weight of variable */
    262 int filterpos; /**< position of event in variable's event filter */
    263};
    264
    265
    266/** data structure to combine two sorting key values */
    267struct sortkeypair
    268{
    269 SCIP_Real key1; /**< first sort key value */
    270 SCIP_Real key2; /**< second sort key value */
    271};
    272typedef struct sortkeypair SORTKEYPAIR;
    273
    274/** status of GUB constraint */
    276{
    277 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
    278 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
    279 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
    280 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
    281 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
    282 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
    285
    286/** status of variable in GUB constraint */
    288{
    289 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
    290 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
    291 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
    292 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
    293 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
    294 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
    297
    298/** data structure of GUB constraints */
    300{
    301 int* gubvars; /**< indices of GUB variables in knapsack constraint */
    302 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
    303 int ngubvars; /**< number of GUB variables */
    304 int gubvarssize; /**< size of gubvars array */
    305};
    307
    308/** data structure of a set of GUB constraints */
    310{
    311 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
    312 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
    313 int ngubconss; /**< number of GUB constraints */
    314 int nvars; /**< number of variables in knapsack constraint */
    315 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
    316 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
    317};
    319
    320/*
    321 * Local methods
    322 */
    323
    324/** comparison method for two sorting key pairs */
    325static
    326SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
    327{
    328 SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
    329 SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
    330
    331 if( sortkeypair1->key1 < sortkeypair2->key1 )
    332 return -1;
    333 else if( sortkeypair1->key1 > sortkeypair2->key1 )
    334 return +1;
    335 else if( sortkeypair1->key2 < sortkeypair2->key2 )
    336 return -1;
    337 else if( sortkeypair1->key2 > sortkeypair2->key2 )
    338 return +1;
    339 else
    340 return 0;
    341}
    342
    343/** creates event data */
    344static
    346 SCIP* scip, /**< SCIP data structure */
    347 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
    348 SCIP_CONS* cons, /**< constraint */
    349 SCIP_Longint weight /**< weight of variable */
    350 )
    351{
    352 assert(eventdata != NULL);
    353
    354 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
    355 (*eventdata)->cons = cons;
    356 (*eventdata)->weight = weight;
    357
    358 return SCIP_OKAY;
    359}
    360
    361/** frees event data */
    362static
    364 SCIP* scip, /**< SCIP data structure */
    365 SCIP_EVENTDATA** eventdata /**< pointer to event data */
    366 )
    367{
    368 assert(eventdata != NULL);
    369
    370 SCIPfreeBlockMemory(scip, eventdata);
    371
    372 return SCIP_OKAY;
    373}
    374
    375/** sorts items in knapsack with nonincreasing weights */
    376static
    378 SCIP_CONSDATA* consdata /**< constraint data */
    379 )
    380{
    381 assert(consdata != NULL);
    382 assert(consdata->nvars == 0 || consdata->vars != NULL);
    383 assert(consdata->nvars == 0 || consdata->weights != NULL);
    384 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
    385 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
    386
    387 if( !consdata->sorted )
    388 {
    389 int pos;
    390 int lastcliquenum;
    391 int v;
    392
    393 /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
    394 * sorted by first array in non-increasing order via sort template */
    396 consdata->weights,
    397 (void**)consdata->vars,
    398 (void**)consdata->eventdata,
    399 consdata->cliquepartition,
    400 consdata->negcliquepartition,
    401 consdata->nvars);
    402
    403 v = consdata->nvars - 1;
    404 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
    405 while( v >= 0 )
    406 {
    407 int w = v - 1;
    408
    409 while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
    410 --w;
    411
    412 if( v - w > 1 )
    413 {
    414 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
    416 (void**)(&(consdata->vars[w+1])),
    417 (void**)(&(consdata->eventdata[w+1])),
    418 &(consdata->cliquepartition[w+1]),
    419 &(consdata->negcliquepartition[w+1]),
    420 SCIPvarComp,
    421 v - w);
    422 }
    423 v = w;
    424 }
    425
    426 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
    427 if( consdata->cliquepartitioned )
    428 {
    429 lastcliquenum = 0;
    430
    431 for( pos = 0; pos < consdata->nvars; ++pos )
    432 {
    433 /* if the clique number in the normal clique at position pos is greater than the last found clique number the
    434 * partition is invalid */
    435 if( consdata->cliquepartition[pos] > lastcliquenum )
    436 {
    437 consdata->cliquepartitioned = FALSE;
    438 break;
    439 }
    440 else if( consdata->cliquepartition[pos] == lastcliquenum )
    441 ++lastcliquenum;
    442 }
    443 }
    444 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
    445 if( consdata->negcliquepartitioned )
    446 {
    447 lastcliquenum = 0;
    448
    449 for( pos = 0; pos < consdata->nvars; ++pos )
    450 {
    451 /* if the clique number in the negated clique at position pos is greater than the last found clique number the
    452 * partition is invalid */
    453 if( consdata->negcliquepartition[pos] > lastcliquenum )
    454 {
    455 consdata->negcliquepartitioned = FALSE;
    456 break;
    457 }
    458 else if( consdata->negcliquepartition[pos] == lastcliquenum )
    459 ++lastcliquenum;
    460 }
    461 }
    462
    463 consdata->sorted = TRUE;
    464 }
    465#ifndef NDEBUG
    466 {
    467 /* check if the weight array is sorted in a non-increasing way */
    468 int i;
    469 for( i = 0; i < consdata->nvars-1; ++i )
    470 assert(consdata->weights[i] >= consdata->weights[i+1]);
    471 }
    472#endif
    473}
    474
    475/** calculates a partition of the variables into cliques */
    476static
    478 SCIP* scip, /**< SCIP data structure */
    479 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
    480 SCIP_CONSDATA* consdata, /**< constraint data */
    481 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
    482 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
    483 )
    484{
    485 SCIP_Bool ispartitionoutdated;
    486 SCIP_Bool isnegpartitionoutdated;
    487 assert(consdata != NULL);
    488 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
    489
    490 /* rerun eventually if number of global cliques increased considerably since last partition */
    491 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
    492 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
    493
    494 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
    495 {
    496 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
    497 consdata->cliquepartition, &consdata->ncliques) );
    498 consdata->cliquepartitioned = TRUE;
    499 consdata->ncliqueslastpart = SCIPgetNCliques(scip);
    500 }
    501
    502 /* rerun eventually if number of global cliques increased considerably since last negated partition */
    503 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
    504 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
    505
    506 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
    507 {
    508 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
    509 consdata->negcliquepartition, &consdata->nnegcliques) );
    510 consdata->negcliquepartitioned = TRUE;
    511 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
    512 }
    513 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
    514 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
    515
    516 return SCIP_OKAY;
    517}
    518
    519/** installs rounding locks for the given variable in the given knapsack constraint */
    520static
    522 SCIP* scip, /**< SCIP data structure */
    523 SCIP_CONS* cons, /**< knapsack constraint */
    524 SCIP_VAR* var /**< variable of constraint entry */
    525 )
    526{
    527 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
    528
    529 return SCIP_OKAY;
    530}
    531
    532/** removes rounding locks for the given variable in the given knapsack constraint */
    533static
    535 SCIP* scip, /**< SCIP data structure */
    536 SCIP_CONS* cons, /**< knapsack constraint */
    537 SCIP_VAR* var /**< variable of constraint entry */
    538 )
    539{
    540 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
    541
    542 return SCIP_OKAY;
    543}
    544
    545/** catches bound change events for variables in knapsack */
    546static
    548 SCIP* scip, /**< SCIP data structure */
    549 SCIP_CONS* cons, /**< constraint */
    550 SCIP_CONSDATA* consdata, /**< constraint data */
    551 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    552 )
    553{
    554 int i;
    555
    556 assert(cons != NULL);
    557 assert(consdata != NULL);
    558 assert(consdata->nvars == 0 || consdata->vars != NULL);
    559 assert(consdata->nvars == 0 || consdata->weights != NULL);
    560 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
    561
    562 for( i = 0; i < consdata->nvars; i++)
    563 {
    564 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
    566 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
    567 }
    568
    569 return SCIP_OKAY;
    570}
    571
    572/** drops bound change events for variables in knapsack */
    573static
    575 SCIP* scip, /**< SCIP data structure */
    576 SCIP_CONSDATA* consdata, /**< constraint data */
    577 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    578 )
    579{
    580 int i;
    581
    582 assert(consdata != NULL);
    583 assert(consdata->nvars == 0 || consdata->vars != NULL);
    584 assert(consdata->nvars == 0 || consdata->weights != NULL);
    585 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
    586
    587 for( i = 0; i < consdata->nvars; i++)
    588 {
    590 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
    591 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
    592 }
    593
    594 return SCIP_OKAY;
    595}
    596
    597/** ensures, that vars and vals arrays can store at least num entries */
    598static
    600 SCIP* scip, /**< SCIP data structure */
    601 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
    602 int num, /**< minimum number of entries to store */
    603 SCIP_Bool transformed /**< is constraint from transformed problem? */
    604 )
    605{
    606 assert(consdata != NULL);
    607 assert(consdata->nvars <= consdata->varssize);
    608
    609 if( num > consdata->varssize )
    610 {
    611 int newsize;
    612
    613 newsize = SCIPcalcMemGrowSize(scip, num);
    614 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
    615 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
    616 if( transformed )
    617 {
    618 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
    619 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
    620 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
    621 }
    622 else
    623 {
    624 assert(consdata->eventdata == NULL);
    625 assert(consdata->cliquepartition == NULL);
    626 assert(consdata->negcliquepartition == NULL);
    627 }
    628 consdata->varssize = newsize;
    629 }
    630 assert(num <= consdata->varssize);
    631
    632 return SCIP_OKAY;
    633}
    634
    635/** updates all weight sums for fixed and unfixed variables */
    636static
    638 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
    639 SCIP_VAR* var, /**< variable for this weight */
    640 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
    641 )
    642{
    643 assert(consdata != NULL);
    644 assert(var != NULL);
    645
    646 consdata->weightsum += weightdelta;
    647
    648 if( SCIPvarGetLbLocal(var) > 0.5 )
    649 consdata->onesweightsum += weightdelta;
    650
    651 assert(consdata->weightsum >= 0);
    652 assert(consdata->onesweightsum >= 0);
    653}
    654
    655/** creates knapsack constraint data */
    656static
    658 SCIP* scip, /**< SCIP data structure */
    659 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
    660 int nvars, /**< number of variables in knapsack */
    661 SCIP_VAR** vars, /**< variables of knapsack */
    662 SCIP_Longint* weights, /**< weights of knapsack items */
    663 SCIP_Longint capacity /**< capacity of knapsack */
    664 )
    665{
    666 int v;
    667 SCIP_Longint constant;
    668
    669 assert(consdata != NULL);
    670
    671 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
    672
    673 constant = 0L;
    674 (*consdata)->vars = NULL;
    675 (*consdata)->weights = NULL;
    676 (*consdata)->nvars = 0;
    677 if( nvars > 0 )
    678 {
    679 SCIP_VAR** varsbuffer;
    680 SCIP_Longint* weightsbuffer;
    681 int k;
    682
    683 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
    684 SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
    685
    686 k = 0;
    687 for( v = 0; v < nvars; ++v )
    688 {
    689 assert(vars[v] != NULL);
    690 assert(SCIPvarIsBinary(vars[v]));
    691
    692 /* all weight have to be non negative */
    693 assert( weights[v] >= 0 );
    694
    695 if( weights[v] > 0 )
    696 {
    697 /* treat fixed variables as constants if problem compression is enabled */
    699 {
    700 /* only if the variable is fixed to 1, we add its weight to the constant */
    701 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
    702 constant += weights[v];
    703 }
    704 else
    705 {
    706 varsbuffer[k] = vars[v];
    707 weightsbuffer[k] = weights[v];
    708 ++k;
    709 }
    710 }
    711 }
    712 assert(k >= 0);
    713 assert(constant >= 0);
    714
    715 (*consdata)->nvars = k;
    716
    717 /* copy the active variables and weights into the constraint data structure */
    718 if( k > 0 )
    719 {
    720 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
    721 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
    722 }
    723
    724 /* free buffer storage */
    725 SCIPfreeBufferArray(scip, &weightsbuffer);
    726 SCIPfreeBufferArray(scip, &varsbuffer);
    727 }
    728
    729 (*consdata)->varssize = (*consdata)->nvars;
    730 (*consdata)->capacity = capacity - constant;
    731 (*consdata)->eventdata = NULL;
    732 (*consdata)->cliquepartition = NULL;
    733 (*consdata)->negcliquepartition = NULL;
    734 (*consdata)->row = NULL;
    735 (*consdata)->nlrow = NULL;
    736 (*consdata)->weightsum = 0;
    737 (*consdata)->onesweightsum = 0;
    738 (*consdata)->ncliques = 0;
    739 (*consdata)->nnegcliques = 0;
    740 (*consdata)->presolvedtiming = 0;
    741 (*consdata)->sorted = FALSE;
    742 (*consdata)->cliquepartitioned = FALSE;
    743 (*consdata)->negcliquepartitioned = FALSE;
    744 (*consdata)->ncliqueslastpart = -1;
    745 (*consdata)->ncliqueslastnegpart = -1;
    746 (*consdata)->merged = FALSE;
    747 (*consdata)->cliquesadded = FALSE;
    748 (*consdata)->varsdeleted = FALSE;
    749 (*consdata)->existmultaggr = FALSE;
    750
    751 /* get transformed variables, if we are in the transformed problem */
    753 {
    754 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
    755
    756 for( v = 0; v < (*consdata)->nvars; v++ )
    757 {
    758 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
    759 assert(var != NULL);
    760 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
    761 }
    762
    763 /* allocate memory for additional data structures */
    764 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
    765 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
    766 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
    767 }
    768
    769 /* calculate sum of weights and capture variables */
    770 for( v = 0; v < (*consdata)->nvars; ++v )
    771 {
    772 /* calculate sum of weights */
    773 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
    774
    775 /* capture variables */
    776 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
    777 }
    778 return SCIP_OKAY;
    779}
    780
    781/** frees knapsack constraint data */
    782static
    784 SCIP* scip, /**< SCIP data structure */
    785 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
    786 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
    787 )
    788{
    789 assert(consdata != NULL);
    790 assert(*consdata != NULL);
    791
    792 if( (*consdata)->row != NULL )
    793 {
    794 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
    795 }
    796 if( (*consdata)->nlrow != NULL )
    797 {
    798 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
    799 }
    800 if( (*consdata)->eventdata != NULL )
    801 {
    802 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
    803 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
    804 }
    805 if( (*consdata)->negcliquepartition != NULL )
    806 {
    807 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
    808 }
    809 if( (*consdata)->cliquepartition != NULL )
    810 {
    811 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
    812 }
    813 if( (*consdata)->vars != NULL )
    814 {
    815 int v;
    816
    817 /* release variables */
    818 for( v = 0; v < (*consdata)->nvars; v++ )
    819 {
    820 assert((*consdata)->vars[v] != NULL);
    821 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
    822 }
    823
    824 assert( (*consdata)->weights != NULL );
    825 assert( (*consdata)->varssize > 0 );
    826 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
    827 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
    828 }
    829
    830 SCIPfreeBlockMemory(scip, consdata);
    831
    832 return SCIP_OKAY;
    833}
    834
    835/** changes a single weight in knapsack constraint data */
    836static
    838 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
    839 int item, /**< item number */
    840 SCIP_Longint newweight /**< new weight of item */
    841 )
    842{
    843 SCIP_Longint oldweight;
    844 SCIP_Longint weightdiff;
    845
    846 assert(consdata != NULL);
    847 assert(0 <= item && item < consdata->nvars);
    848
    849 oldweight = consdata->weights[item];
    850 weightdiff = newweight - oldweight;
    851 consdata->weights[item] = newweight;
    852
    853 /* update weight sums for all and fixed variables */
    854 updateWeightSums(consdata, consdata->vars[item], weightdiff);
    855
    856 if( consdata->eventdata != NULL )
    857 {
    858 assert(consdata->eventdata[item] != NULL);
    859 assert(consdata->eventdata[item]->weight == oldweight);
    860 consdata->eventdata[item]->weight = newweight;
    861 }
    862
    863 consdata->presolvedtiming = 0;
    864 consdata->sorted = FALSE;
    865
    866 /* recalculate cliques extraction after a weight was increased */
    867 if( oldweight < newweight )
    868 {
    869 consdata->cliquesadded = FALSE;
    870 }
    871}
    872
    873/** creates LP row corresponding to knapsack constraint */
    874static
    876 SCIP* scip, /**< SCIP data structure */
    877 SCIP_CONS* cons /**< knapsack constraint */
    878 )
    879{
    880 SCIP_CONSDATA* consdata;
    881 int i;
    882
    883 consdata = SCIPconsGetData(cons);
    884 assert(consdata != NULL);
    885 assert(consdata->row == NULL);
    886
    887 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
    888 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
    890
    891 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
    892 for( i = 0; i < consdata->nvars; ++i )
    893 {
    894 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
    895 }
    896 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
    897
    898 return SCIP_OKAY;
    899}
    900
    901/** adds linear relaxation of knapsack constraint to the LP */
    902static
    904 SCIP* scip, /**< SCIP data structure */
    905 SCIP_CONS* cons, /**< knapsack constraint */
    906 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
    907 )
    908{
    909 SCIP_CONSDATA* consdata;
    910
    911 assert( cutoff != NULL );
    912 *cutoff = FALSE;
    913
    914 consdata = SCIPconsGetData(cons);
    915 assert(consdata != NULL);
    916
    917 if( consdata->row == NULL )
    918 {
    920 }
    921 assert(consdata->row != NULL);
    922
    923 /* insert LP row as cut */
    924 if( !SCIProwIsInLP(consdata->row) )
    925 {
    926 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
    927 SCIPconsGetName(cons), consdata->capacity);
    928 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, consdata->row, NULL) ) );
    929 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
    930 }
    931
    932 return SCIP_OKAY;
    933}
    934
    935/** adds knapsack constraint as row to the NLP, if not added yet */
    936static
    938 SCIP* scip, /**< SCIP data structure */
    939 SCIP_CONS* cons /**< knapsack constraint */
    940 )
    941{
    942 SCIP_CONSDATA* consdata;
    943
    944 assert(SCIPisNLPConstructed(scip));
    945
    946 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
    947 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
    948 return SCIP_OKAY;
    949
    950 consdata = SCIPconsGetData(cons);
    951 assert(consdata != NULL);
    952
    953 if( consdata->nlrow == NULL )
    954 {
    955 SCIP_Real* coefs;
    956 int i;
    957
    958 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
    959 for( i = 0; i < consdata->nvars; ++i )
    960 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
    961
    962 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
    963 consdata->nvars, consdata->vars, coefs, NULL,
    964 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
    965
    966 assert(consdata->nlrow != NULL);
    967
    968 SCIPfreeBufferArray(scip, &coefs);
    969 }
    970
    971 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
    972 {
    973 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
    974 }
    975
    976 return SCIP_OKAY;
    977}
    978
    979/** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
    980static
    982 SCIP* scip, /**< SCIP data structure */
    983 SCIP_CONS* cons, /**< constraint to check */
    984 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
    985 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
    986 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
    987 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
    988 )
    989{
    990 SCIP_CONSDATA* consdata;
    991
    992 assert(violated != NULL);
    993
    994 consdata = SCIPconsGetData(cons);
    995 assert(consdata != NULL);
    996
    997 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
    998 SCIPconsGetName(cons), (void*)sol, checklprows);
    999
    1000 *violated = FALSE;
    1001
    1002 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
    1003 {
    1004 SCIP_Real normsum = 0.0;
    1005 SCIP_Real hugesum = 0.0;
    1006 SCIP_Real absviol;
    1007 SCIP_Real relviol;
    1008 int v;
    1009
    1010 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
    1011 * enforcement
    1012 */
    1013 if( sol == NULL )
    1014 {
    1015 SCIP_CALL( SCIPincConsAge(scip, cons) );
    1016 }
    1017
    1018 /* sum separately over normal and huge weight contributions in order to reduce numerical cancellation */
    1019 for( v = consdata->nvars - 1; v >= 0; --v )
    1020 {
    1021 assert(SCIPvarIsBinary(consdata->vars[v]));
    1022
    1023 if( SCIPisHugeValue(scip, (SCIP_Real)consdata->weights[v]) )
    1024 hugesum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
    1025 else
    1026 normsum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
    1027 }
    1028
    1029 /* calculate constraint violation and update it in solution */
    1030 normsum += hugesum;
    1031
    1032 if( normsum > consdata->capacity )
    1033 {
    1034 absviol = normsum - consdata->capacity;
    1035 relviol = SCIPrelDiff(normsum, (SCIP_Real)consdata->capacity);
    1036 }
    1037 else
    1038 {
    1039 absviol = 0.0;
    1040 relviol = 0.0;
    1041 }
    1042
    1043 if( sol != NULL )
    1044 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
    1045
    1046 if( SCIPisFeasPositive(scip, absviol) )
    1047 {
    1048 *violated = TRUE;
    1049
    1050 /* only reset constraint age if we are in enforcement */
    1051 if( sol == NULL )
    1052 {
    1054 }
    1055
    1056 if( printreason )
    1057 {
    1058 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
    1059
    1060 SCIPinfoMessage(scip, NULL, ";\n");
    1061 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
    1062 }
    1063 }
    1064 }
    1065
    1066 return SCIP_OKAY;
    1067}
    1068
    1069/* IDX computes the integer index for the optimal solution array */
    1070#define IDX(j,d) ((j)*(intcap)+(d))
    1071
    1072/** solves knapsack problem in maximization form exactly using dynamic programming;
    1073 * if needed, one can provide arrays to store all selected items and all not selected items
    1074 *
    1075 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
    1076 *
    1077 * @note the algorithm will first compute a greedy solution and terminate
    1078 * if the greedy solution is proven to be optimal.
    1079 * The dynamic programming algorithm runs with a time and space complexity
    1080 * of O(nitems * capacity).
    1081 *
    1082 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
    1083 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
    1084 * to be checked whether they are faster and whether they can reconstruct the solution.
    1085 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
    1086 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
    1087 * This could be implemented, however, it would be technically a bit cumbersome,
    1088 * since one needs the greedy solution and the LP-value for this.
    1089 * This is currently only available after the redundant items have already been sorted out.
    1090 */
    1092 SCIP* scip, /**< SCIP data structure */
    1093 int nitems, /**< number of available items */
    1094 SCIP_Longint* weights, /**< item weights */
    1095 SCIP_Real* profits, /**< item profits */
    1096 SCIP_Longint capacity, /**< capacity of knapsack */
    1097 int* items, /**< item numbers */
    1098 int* solitems, /**< array to store items in solution, or NULL */
    1099 int* nonsolitems, /**< array to store items not in solution, or NULL */
    1100 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
    1101 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
    1102 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
    1103 SCIP_Bool* success /**< pointer to store if an error occurred during solving
    1104 * (normally a memory problem) */
    1105 )
    1106{
    1107 SCIP_RETCODE retcode;
    1108 SCIP_Real* tempsort;
    1109 SCIP_Real* optvalues;
    1110 int intcap;
    1111 int d;
    1112 int j;
    1113 int greedymedianpos;
    1114 SCIP_Longint weightsum;
    1115 int* myitems;
    1116 SCIP_Longint* myweights;
    1117 SCIP_Real* realweights;
    1118 int* allcurrminweight;
    1119 SCIP_Real* myprofits;
    1120 int nmyitems;
    1121 SCIP_Longint gcd;
    1122 SCIP_Longint minweight;
    1123 SCIP_Longint maxweight;
    1124 int currminweight;
    1125 SCIP_Longint greedysolweight;
    1126 SCIP_Real greedysolvalue;
    1127 SCIP_Real greedyupperbound;
    1128 SCIP_Bool eqweights;
    1129 SCIP_Bool intprofits;
    1130 int lastitem; /* last item processed in DP (for early termination) */
    1131
    1132 assert(weights != NULL);
    1133 assert(profits != NULL);
    1134 assert(capacity >= 0);
    1135 assert(items != NULL);
    1136 assert(nitems >= 0);
    1137 assert(success != NULL);
    1138
    1139 *success = TRUE;
    1140
    1141#ifndef NDEBUG
    1142 for( j = nitems - 1; j >= 0; --j )
    1143 assert(weights[j] >= 0);
    1144#endif
    1145
    1146 SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
    1147
    1148 /* initializing solution value */
    1149 if( solval != NULL )
    1150 *solval = 0.0;
    1151
    1152 /* init solution information */
    1153 if( solitems != NULL )
    1154 {
    1155 assert(items != NULL);
    1156 assert(nsolitems != NULL);
    1157 assert(nonsolitems != NULL);
    1158 assert(nnonsolitems != NULL);
    1159
    1160 *nnonsolitems = 0;
    1161 *nsolitems = 0;
    1162 }
    1163
    1164 /* allocate temporary memory */
    1165 SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
    1166 SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
    1167 SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
    1168 nmyitems = 0;
    1169 weightsum = 0;
    1170 minweight = SCIP_LONGINT_MAX;
    1171 maxweight = 0;
    1172
    1173 /* remove unnecessary items */
    1174 for( j = 0; j < nitems; ++j )
    1175 {
    1176 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
    1177
    1178 /* item does not fit */
    1179 if( weights[j] > capacity )
    1180 {
    1181 if( solitems != NULL )
    1182 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
    1183 }
    1184 /* item is not profitable */
    1185 else if( profits[j] <= 0.0 )
    1186 {
    1187 if( solitems != NULL )
    1188 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
    1189 }
    1190 /* item always fits */
    1191 else if( weights[j] == 0 )
    1192 {
    1193 if( solitems != NULL )
    1194 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
    1195
    1196 if( solval != NULL )
    1197 *solval += profits[j];
    1198 }
    1199 /* all important items */
    1200 else
    1201 {
    1202 myweights[nmyitems] = weights[j];
    1203 myprofits[nmyitems] = profits[j];
    1204 myitems[nmyitems] = items[j];
    1205
    1206 /* remember smallest item */
    1207 if( myweights[nmyitems] < minweight )
    1208 minweight = myweights[nmyitems];
    1209
    1210 /* remember bigest item */
    1211 if( myweights[nmyitems] > maxweight )
    1212 maxweight = myweights[nmyitems];
    1213
    1214 weightsum += myweights[nmyitems];
    1215 ++nmyitems;
    1216 }
    1217 }
    1218
    1219 intprofits = TRUE;
    1220 /* check if all profits are integer to strengthen the upper bound on the greedy solution */
    1221 for( j = 0; j < nmyitems && intprofits; ++j )
    1222 intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
    1223
    1224 /* if no item is left then goto end */
    1225 if( nmyitems == 0 )
    1226 {
    1227 SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
    1228
    1229 goto TERMINATE;
    1230 }
    1231
    1232 /* if all items fit, we also do not need to do the expensive stuff later on */
    1233 if( weightsum > 0 && weightsum <= capacity )
    1234 {
    1235 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
    1236
    1237 for( j = nmyitems - 1; j >= 0; --j )
    1238 {
    1239 if( solitems != NULL )
    1240 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
    1241
    1242 if( solval != NULL )
    1243 *solval += myprofits[j];
    1244 }
    1245
    1246 goto TERMINATE;
    1247 }
    1248
    1249 assert(0 < minweight && minweight <= capacity );
    1250 assert(0 < maxweight && maxweight <= capacity);
    1251
    1252 /* make weights relatively prime */
    1253 eqweights = TRUE;
    1254 if( maxweight > 1 )
    1255 {
    1256 /* determine greatest common divisor */
    1257 gcd = myweights[nmyitems - 1];
    1258 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
    1259 gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
    1260
    1261 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
    1262
    1263 /* divide by greatest common divisor */
    1264 if( gcd > 1 )
    1265 {
    1266 for( j = nmyitems - 1; j >= 0; --j )
    1267 {
    1268 myweights[j] /= gcd;
    1269 eqweights = eqweights && (myweights[j] == 1);
    1270 }
    1271 capacity /= gcd;
    1272 minweight /= gcd;
    1273 }
    1274 else
    1275 eqweights = FALSE;
    1276 }
    1277 assert(minweight <= capacity);
    1278
    1279 /* if only one item fits, then take the best */
    1280 if( minweight > capacity / 2 )
    1281 {
    1282 int p;
    1283
    1284 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
    1285
    1286 p = nmyitems - 1;
    1287
    1288 /* find best item */
    1289 for( j = nmyitems - 2; j >= 0; --j )
    1290 {
    1291 if( myprofits[j] > myprofits[p] )
    1292 p = j;
    1293 }
    1294
    1295 /* update solution information */
    1296 if( solitems != NULL )
    1297 {
    1298 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
    1299
    1300 solitems[(*nsolitems)++] = myitems[p];
    1301 for( j = nmyitems - 1; j >= 0; --j )
    1302 {
    1303 if( j != p )
    1304 nonsolitems[(*nnonsolitems)++] = myitems[j];
    1305 }
    1306 }
    1307 /* update solution value */
    1308 if( solval != NULL )
    1309 *solval += myprofits[p];
    1310
    1311 goto TERMINATE;
    1312 }
    1313
    1314 /* if all items have the same weight, then take the best */
    1315 if( eqweights )
    1316 {
    1317 SCIP_Real addval = 0.0;
    1318
    1319 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
    1320
    1321 SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
    1322
    1323 /* update solution information */
    1324 if( solitems != NULL || solval != NULL )
    1325 {
    1326 SCIP_Longint i;
    1327
    1328 /* if all items would fit we had handled this case before */
    1329 assert((SCIP_Longint) nmyitems > capacity);
    1330 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
    1331
    1332 /* take the first best items into the solution */
    1333 for( i = capacity - 1; i >= 0; --i )
    1334 {
    1335 if( solitems != NULL )
    1336 solitems[(*nsolitems)++] = myitems[i];
    1337 addval += myprofits[i];
    1338 }
    1339
    1340 if( solitems != NULL )
    1341 {
    1342 /* the rest are not in the solution */
    1343 for( i = nmyitems - 1; i >= capacity; --i )
    1344 nonsolitems[(*nnonsolitems)++] = myitems[i];
    1345 }
    1346 }
    1347 /* update solution value */
    1348 if( solval != NULL )
    1349 {
    1350 assert(addval > 0.0);
    1351 *solval += addval;
    1352 }
    1353
    1354 goto TERMINATE;
    1355 }
    1356
    1357 SCIPdebugMsg(scip, "Determine greedy solution.\n");
    1358
    1359 /* sort myitems (plus corresponding arrays myweights and myprofits) such that
    1360 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
    1361 */
    1362 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
    1363 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
    1364
    1365 for( j = 0; j < nmyitems; ++j )
    1366 {
    1367 tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
    1368 realweights[j] = (SCIP_Real)myweights[j];
    1369 }
    1370
    1371 SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
    1372 (SCIP_Real)capacity, nmyitems, &greedymedianpos);
    1373
    1374 SCIPfreeBufferArray(scip, &realweights);
    1375 SCIPfreeBufferArray(scip, &tempsort);
    1376
    1377 /* initialize values for greedy solution information */
    1378 greedysolweight = 0;
    1379 greedysolvalue = 0.0;
    1380
    1381 /* determine greedy solution */
    1382 for( j = 0; j < greedymedianpos; ++j )
    1383 {
    1384 assert(myweights[j] <= capacity);
    1385
    1386 /* update greedy solution weight and value */
    1387 greedysolweight += myweights[j];
    1388 greedysolvalue += myprofits[j];
    1389 }
    1390
    1391 assert(0 < greedysolweight && greedysolweight <= capacity);
    1392 assert(greedysolvalue > 0.0);
    1393
    1394 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
    1395 * - the greedy solution reaches the capacity, because then the LP solution is integral;
    1396 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
    1397 greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
    1398 if( intprofits )
    1399 greedyupperbound = SCIPfloor(scip, greedyupperbound);
    1400 if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
    1401 {
    1402 SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
    1403
    1404 /* update solution information */
    1405 if( solitems != NULL )
    1406 {
    1407 int l;
    1408
    1409 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
    1410
    1411 /* collect items */
    1412 for( l = 0; l < j; ++l )
    1413 solitems[(*nsolitems)++] = myitems[l];
    1414 for ( ; l < nmyitems; ++l )
    1415 nonsolitems[(*nnonsolitems)++] = myitems[l];
    1416 }
    1417 /* update solution value */
    1418 if( solval != NULL )
    1419 {
    1420 assert(greedysolvalue > 0.0);
    1421 *solval += greedysolvalue;
    1422 }
    1423
    1424 goto TERMINATE;
    1425 }
    1426
    1427 /* in the following table we do not need the first minweight columns */
    1428 capacity -= (minweight - 1);
    1429
    1430 /* we can only handle integers */
    1431 if( capacity >= INT_MAX )
    1432 {
    1433 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
    1434
    1435 *success = FALSE;
    1436 goto TERMINATE;
    1437 }
    1438 assert(capacity < INT_MAX);
    1439
    1440 intcap = (int)capacity;
    1441 assert(intcap >= 0);
    1442 assert(nmyitems > 0);
    1443 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
    1444
    1445 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
    1446 * computing the size for the allocation
    1447 */
    1448 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*/
    1449 {
    1450 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
    1451
    1452 *success = FALSE;
    1453 goto TERMINATE;
    1454 }
    1455
    1456 /* allocate temporary memory and check for memory exceedance */
    1457 retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
    1458 if( retcode == SCIP_NOMEMORY )
    1459 {
    1460 SCIPdebugMsg(scip, "Did not get enough memory.\n");
    1461
    1462 *success = FALSE;
    1463 goto TERMINATE;
    1464 }
    1465 else
    1466 {
    1467 SCIP_CALL( retcode );
    1468 }
    1469
    1470 SCIPdebugMsg(scip, "Start real exact algorithm.\n");
    1471
    1472 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
    1473 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
    1474 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
    1475 * 'nmyitem' values
    1476 */
    1477 SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
    1478 assert(myweights[0] - minweight < INT_MAX);
    1479 currminweight = (int) (myweights[0] - minweight);
    1480 allcurrminweight[0] = currminweight;
    1481
    1482 /* fills first row of dynamic programming table with optimal values */
    1483 for( d = currminweight; d < intcap; ++d )
    1484 optvalues[d] = myprofits[0];
    1485
    1486 /* by default, all items are processed */
    1487 lastitem = nmyitems - 1;
    1488
    1489 /* fills dynamic programming table with optimal values */
    1490 for( j = 1; j < nmyitems; ++j )
    1491 {
    1492 int intweight;
    1493
    1494 /* compute important part of weight, which will be represented in the table */
    1495 intweight = (int)(myweights[j] - minweight);
    1496 assert(0 <= intweight && intweight < intcap);
    1497
    1498 /* copy all nonzeros from row above */
    1499 for( d = currminweight; d < intweight && d < intcap; ++d )
    1500 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
    1501
    1502 /* update corresponding row */
    1503 for( d = intweight; d < intcap; ++d )
    1504 {
    1505 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
    1506 if( d < currminweight )
    1507 optvalues[IDX(j,d)] = myprofits[j];
    1508 else
    1509 {
    1510 SCIP_Real sumprofit;
    1511
    1512 if( d - myweights[j] < currminweight )
    1513 sumprofit = myprofits[j];
    1514 else
    1515 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
    1516
    1517 optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
    1518 }
    1519 }
    1520
    1521 /* update currminweight */
    1522 if( intweight < currminweight )
    1523 currminweight = intweight;
    1524
    1525 allcurrminweight[j] = currminweight;
    1526
    1527 /* early termination: if current best value reaches the LP upper bound, we have found an optimal solution */
    1528 if( intprofits && optvalues[IDX(j, intcap - 1)] >= greedyupperbound )
    1529 {
    1530 lastitem = j;
    1531 break;
    1532 }
    1533 }
    1534
    1535 /* update optimal solution by following the table */
    1536 if( solitems != NULL )
    1537 {
    1538 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
    1539 d = intcap - 1;
    1540
    1541 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
    1542
    1543 /* items after lastitem were not processed due to early termination; they are not in the solution */
    1544 for( j = nmyitems - 1; j > lastitem; --j )
    1545 nonsolitems[(*nnonsolitems)++] = myitems[j];
    1546
    1547 /* insert all items in (non-) solution vector */
    1548 for( j = lastitem; j > 0; --j )
    1549 {
    1550 /* if the following condition holds this means all remaining items does not fit anymore */
    1551 if( d < allcurrminweight[j] )
    1552 {
    1553 /* we cannot have exceeded our capacity */
    1554 assert((SCIP_Longint) d >= -minweight);
    1555 break;
    1556 }
    1557
    1558 /* collect solution items; the first condition means that no further item can fit anymore, but this does */
    1559 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
    1560 {
    1561 solitems[(*nsolitems)++] = myitems[j];
    1562
    1563 /* check that we do not have an underflow */
    1564 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
    1565 d = (int)(d - myweights[j]);
    1566 }
    1567 /* collect non-solution items */
    1568 else
    1569 nonsolitems[(*nnonsolitems)++] = myitems[j];
    1570 }
    1571
    1572 /* insert remaining items */
    1573 if( d >= allcurrminweight[j] )
    1574 {
    1575 assert(j == 0);
    1576 solitems[(*nsolitems)++] = myitems[j];
    1577 }
    1578 else
    1579 {
    1580 assert(j >= 0);
    1581 assert(d < allcurrminweight[j]);
    1582
    1583 for( ; j >= 0; --j )
    1584 nonsolitems[(*nnonsolitems)++] = myitems[j];
    1585 }
    1586
    1587 assert(*nsolitems + *nnonsolitems == nitems);
    1588 }
    1589
    1590 /* update solution value */
    1591 if( solval != NULL )
    1592 *solval += optvalues[IDX(lastitem, intcap - 1)];
    1593 SCIPfreeBufferArray(scip, &allcurrminweight);
    1594
    1595 /* free all temporary memory */
    1596 SCIPfreeBufferArray(scip, &optvalues);
    1597
    1598 TERMINATE:
    1599 SCIPfreeBufferArray(scip, &myitems);
    1600 SCIPfreeBufferArray(scip, &myprofits);
    1601 SCIPfreeBufferArray(scip, &myweights);
    1602
    1603 return SCIP_OKAY;
    1604}
    1605
    1606/** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
    1607 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
    1608 * selected items
    1609 */
    1611 SCIP* scip, /**< SCIP data structure */
    1612 int nitems, /**< number of available items */
    1613 SCIP_Longint* weights, /**< item weights */
    1614 SCIP_Real* profits, /**< item profits */
    1615 SCIP_Longint capacity, /**< capacity of knapsack */
    1616 int* items, /**< item numbers */
    1617 int* solitems, /**< array to store items in solution, or NULL */
    1618 int* nonsolitems, /**< array to store items not in solution, or NULL */
    1619 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
    1620 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
    1621 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
    1622 )
    1623{
    1624 SCIP_Real* tempsort;
    1625 SCIP_Longint solitemsweight;
    1626 SCIP_Real* realweights;
    1627 int j;
    1628 int criticalindex;
    1629
    1630 assert(weights != NULL);
    1631 assert(profits != NULL);
    1632 assert(capacity >= 0);
    1633 assert(items != NULL);
    1634 assert(nitems >= 0);
    1635
    1636 if( solitems != NULL )
    1637 {
    1638 *nsolitems = 0;
    1639 *nnonsolitems = 0;
    1640 }
    1641 if( solval != NULL )
    1642 *solval = 0.0;
    1643
    1644 /* initialize data for median search */
    1645 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
    1646 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
    1647 for( j = nitems - 1; j >= 0; --j )
    1648 {
    1649 tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
    1650 realweights[j] = (SCIP_Real)weights[j];
    1651 }
    1652
    1653 /* partially sort indices such that all elements that are larger than the break item appear first */
    1654 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
    1655
    1656 /* selects items as long as they fit into the knapsack */
    1657 solitemsweight = 0;
    1658 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
    1659 {
    1660 if( solitems != NULL )
    1661 solitems[(*nsolitems)++] = items[j];
    1662
    1663 if( solval != NULL )
    1664 (*solval) += profits[j];
    1665 solitemsweight += weights[j];
    1666 }
    1667 if ( solitems != NULL )
    1668 {
    1669 for( ; j < nitems; j++ )
    1670 nonsolitems[(*nnonsolitems)++] = items[j];
    1671 }
    1672
    1673 SCIPfreeBufferArray(scip, &realweights);
    1674 SCIPfreeBufferArray(scip, &tempsort);
    1675
    1676 return SCIP_OKAY;
    1677}
    1678
    1679#ifdef SCIP_DEBUG
    1680/** prints all nontrivial GUB constraints and their LP solution values */
    1681static
    1682void GUBsetPrint(
    1683 SCIP* scip, /**< SCIP data structure */
    1684 SCIP_GUBSET* gubset, /**< GUB set data structure */
    1685 SCIP_VAR** vars, /**< variables in knapsack constraint */
    1686 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
    1687 )
    1688{
    1689 int nnontrivialgubconss;
    1690 int c;
    1691
    1692 nnontrivialgubconss = 0;
    1693
    1694 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
    1695
    1696 /* print out all nontrivial GUB constraints, i.e., with more than one variable */
    1697 for( c = 0; c < gubset->ngubconss; c++ )
    1698 {
    1699 SCIP_Real gubsolval;
    1700
    1701 assert(gubset->gubconss[c]->ngubvars >= 0);
    1702
    1703 /* nontrivial GUB */
    1704 if( gubset->gubconss[c]->ngubvars > 1 )
    1705 {
    1706 int v;
    1707
    1708 gubsolval = 0.0;
    1709 SCIPdebugMsg(scip, " GUB<%d>:\n", c);
    1710
    1711 /* print GUB var */
    1712 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
    1713 {
    1714 int currentvar;
    1715
    1716 currentvar = gubset->gubconss[c]->gubvars[v];
    1717 if( solvals != NULL )
    1718 {
    1719 gubsolval += solvals[currentvar];
    1720 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
    1721 }
    1722 else
    1723 {
    1724 SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
    1725 }
    1726 }
    1727
    1728 /* check whether LP solution satisfies the GUB constraint */
    1729 if( solvals != NULL )
    1730 {
    1731 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
    1732 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
    1733 }
    1734 else
    1735 {
    1736 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
    1737 }
    1738 nnontrivialgubconss++;
    1739 }
    1740 }
    1741
    1742 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
    1743}
    1744#endif
    1745
    1746/** creates an empty GUB constraint */
    1747static
    1749 SCIP* scip, /**< SCIP data structure */
    1750 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
    1751 )
    1752{
    1753 assert(scip != NULL);
    1754 assert(gubcons != NULL);
    1755
    1756 /* allocate memory for GUB constraint data structures */
    1757 SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
    1758 (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
    1759 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
    1760 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
    1761
    1762 (*gubcons)->ngubvars = 0;
    1763
    1764 return SCIP_OKAY;
    1765}
    1766
    1767/** frees GUB constraint */
    1768static
    1770 SCIP* scip, /**< SCIP data structure */
    1771 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
    1772 )
    1773{
    1774 assert(scip != NULL);
    1775 assert(gubcons != NULL);
    1776 assert((*gubcons)->gubvars != NULL);
    1777 assert((*gubcons)->gubvarsstatus != NULL);
    1778
    1779 /* free allocated memory */
    1780 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
    1781 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
    1782 SCIPfreeBuffer(scip, gubcons);
    1783}
    1784
    1785/** adds variable to given GUB constraint */
    1786static
    1788 SCIP* scip, /**< SCIP data structure */
    1789 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
    1790 int var /**< index of given variable in knapsack constraint */
    1791 )
    1792{
    1793 assert(scip != NULL);
    1794 assert(gubcons != NULL);
    1795 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
    1796 assert(gubcons->gubvars != NULL);
    1797 assert(gubcons->gubvarsstatus != NULL);
    1798 assert(var >= 0);
    1799
    1800 /* add variable to GUB constraint */
    1801 gubcons->gubvars[gubcons->ngubvars] = var;
    1802 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
    1803 gubcons->ngubvars++;
    1804
    1805 /* increase space allocated to GUB constraint if the number of variables reaches the size */
    1806 if( gubcons->ngubvars == gubcons->gubvarssize )
    1807 {
    1808 int newlen;
    1809
    1810 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
    1811 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
    1812 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
    1813
    1814 gubcons->gubvarssize = newlen;
    1815 }
    1816
    1817 return SCIP_OKAY;
    1818}
    1819
    1820/** deletes variable from its current GUB constraint */
    1821static
    1823 SCIP* scip, /**< SCIP data structure */
    1824 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
    1825 int var, /**< index of given variable in knapsack constraint */
    1826 int gubvarsidx /**< index of the variable in its current GUB constraint */
    1827 )
    1828{
    1829 assert(scip != NULL);
    1830 assert(gubcons != NULL);
    1831 assert(var >= 0);
    1832 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
    1833 assert(gubcons->ngubvars >= gubvarsidx+1);
    1834 assert(gubcons->gubvars[gubvarsidx] == var);
    1835
    1836 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
    1837 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
    1838 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
    1839 gubcons->ngubvars--;
    1840
    1841 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
    1842 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
    1843 {
    1844 int newlen;
    1845
    1846 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
    1847
    1848 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
    1849 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
    1850
    1851 gubcons->gubvarssize = newlen;
    1852 }
    1853
    1854 return SCIP_OKAY;
    1855}
    1856
    1857/** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
    1858static
    1860 SCIP* scip, /**< SCIP data structure */
    1861 SCIP_GUBSET* gubset, /**< GUB set data structure */
    1862 SCIP_VAR** vars, /**< variables in knapsack constraint */
    1863 int var, /**< index of given variable in knapsack constraint */
    1864 int oldgubcons, /**< index of old GUB constraint of given variable */
    1865 int newgubcons /**< index of new GUB constraint of given variable */
    1866 )
    1867{
    1868 int oldgubvaridx;
    1869 int replacevar;
    1870 int j;
    1871
    1872 assert(scip != NULL);
    1873 assert(gubset != NULL);
    1874 assert(var >= 0);
    1875 assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
    1876 assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
    1877 assert(oldgubcons != newgubcons);
    1878 assert(gubset->gubconssidx[var] == oldgubcons);
    1879 assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
    1880 assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
    1881
    1882 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
    1883
    1884 oldgubvaridx = gubset->gubvarsidx[var];
    1885
    1886 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
    1887 SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
    1888
    1889 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
    1890 * replacement variable is given by old position of the deleted variable
    1891 */
    1892 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
    1893 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
    1894 gubset->gubvarsidx[replacevar] = oldgubvaridx;
    1895
    1896 /* add variable to the end of new GUB constraint */
    1897 SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
    1898 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
    1899
    1900 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
    1901 gubset->gubconssidx[var] = newgubcons;
    1902 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
    1903
    1904 /* delete old GUB constraint if it became empty */
    1905 if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
    1906 {
    1907 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
    1908#ifdef SCIP_DEBUG
    1909 GUBsetPrint(scip, gubset, vars, NULL);
    1910#endif
    1911
    1912 /* free old GUB constraint */
    1913 GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
    1914
    1915 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
    1916 if( oldgubcons != gubset->ngubconss-1 )
    1917 {
    1918 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
    1919 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
    1920
    1921 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
    1922 * replacement GUB is given by old position of the deleted GUB
    1923 */
    1924 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
    1925 {
    1926 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
    1927 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
    1928 }
    1929 }
    1930
    1931 /* update number of GUB constraints */
    1932 gubset->ngubconss--;
    1933
    1934 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
    1935 * (because it was at the end of the GUB constraint array)
    1936 */
    1937 assert(gubset->gubconssidx[var] == newgubcons
    1938 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
    1939 }
    1940#ifndef NDEBUG
    1941 else
    1942 assert(gubset->gubconssidx[var] == newgubcons);
    1943#endif
    1944
    1945 return SCIP_OKAY;
    1946}
    1947
    1948/** swaps two variables in the same GUB constraint */
    1949static
    1951 SCIP* scip, /**< SCIP data structure */
    1952 SCIP_GUBSET* gubset, /**< GUB set data structure */
    1953 int var1, /**< first variable to be swapped */
    1954 int var2 /**< second variable to be swapped */
    1955 )
    1956{
    1957 int gubcons;
    1958 int var1idx;
    1959 GUBVARSTATUS var1status;
    1960 int var2idx;
    1961 GUBVARSTATUS var2status;
    1962
    1963 assert(scip != NULL);
    1964 assert(gubset != NULL);
    1965
    1966 gubcons = gubset->gubconssidx[var1];
    1967 assert(gubcons == gubset->gubconssidx[var2]);
    1968
    1969 /* nothing to be done if both variables are the same */
    1970 if( var1 == var2 )
    1971 return;
    1972
    1973 /* swap index and status of variables in GUB constraint */
    1974 var1idx = gubset->gubvarsidx[var1];
    1975 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
    1976 var2idx = gubset->gubvarsidx[var2];
    1977 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
    1978
    1979 gubset->gubvarsidx[var1] = var2idx;
    1980 gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
    1981 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
    1982
    1983 gubset->gubvarsidx[var2] = var1idx;
    1984 gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
    1985 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
    1986}
    1987
    1988/** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
    1989static
    1991 SCIP* scip, /**< SCIP data structure */
    1992 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
    1993 int nvars, /**< number of variables in the knapsack constraint */
    1994 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    1995 SCIP_Longint capacity /**< capacity of knapsack */
    1996 )
    1997{
    1998 int i;
    1999
    2000 assert(scip != NULL);
    2001 assert(gubset != NULL);
    2002 assert(nvars > 0);
    2003 assert(weights != NULL);
    2004 assert(capacity >= 0);
    2005
    2006 /* allocate memory for GUB set data structures */
    2007 SCIP_CALL( SCIPallocBuffer(scip, gubset) );
    2008 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
    2009 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
    2010 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
    2011 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
    2012 (*gubset)->ngubconss = nvars;
    2013 (*gubset)->nvars = nvars;
    2014
    2015 /* initialize the set of GUB constraints */
    2016 for( i = 0; i < nvars; i++ )
    2017 {
    2018 /* assign each variable to a new (trivial) GUB constraint */
    2019 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
    2020 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
    2021
    2022 /* set status of GUB constraint to initial */
    2023 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
    2024
    2025 (*gubset)->gubconssidx[i] = i;
    2026 (*gubset)->gubvarsidx[i] = 0;
    2027 assert((*gubset)->gubconss[i]->ngubvars == 1);
    2028
    2029 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
    2030 if( weights[i] > capacity )
    2031 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
    2032 }
    2033
    2034 return SCIP_OKAY;
    2035}
    2036
    2037/** frees GUB set data structure */
    2038static
    2040 SCIP* scip, /**< SCIP data structure */
    2041 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
    2042 )
    2043{
    2044 int i;
    2045
    2046 assert(scip != NULL);
    2047 assert(gubset != NULL);
    2048 assert((*gubset)->gubconss != NULL);
    2049 assert((*gubset)->gubconsstatus != NULL);
    2050 assert((*gubset)->gubconssidx != NULL);
    2051 assert((*gubset)->gubvarsidx != NULL);
    2052
    2053 /* free all GUB constraints */
    2054 for( i = (*gubset)->ngubconss-1; i >= 0; --i )
    2055 {
    2056 assert((*gubset)->gubconss[i] != NULL);
    2057 GUBconsFree(scip, &(*gubset)->gubconss[i]);
    2058 }
    2059
    2060 /* free allocated memory */
    2061 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
    2062 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
    2063 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
    2064 SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
    2065 SCIPfreeBuffer(scip, gubset);
    2066}
    2067
    2068#ifndef NDEBUG
    2069/** checks whether GUB set data structure is consistent */
    2070static
    2072 SCIP* scip, /**< SCIP data structure */
    2073 SCIP_GUBSET* gubset, /**< GUB set data structure */
    2074 SCIP_VAR** vars /**< variables in the knapsack constraint */
    2075 )
    2076{
    2077 int i;
    2078 int gubconsidx;
    2079 int gubvaridx;
    2080 SCIP_VAR* var1;
    2081 SCIP_VAR* var2;
    2082 SCIP_Bool var1negated;
    2083 SCIP_Bool var2negated;
    2084
    2085 assert(scip != NULL);
    2086 assert(gubset != NULL);
    2087
    2088 SCIPdebugMsg(scip, " GUB set consistency check:\n");
    2089
    2090 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
    2091 for( i = 0; i < gubset->nvars; i++ )
    2092 {
    2093 gubconsidx = gubset->gubconssidx[i];
    2094 gubvaridx = gubset->gubvarsidx[i];
    2095
    2096 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
    2097 {
    2098 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
    2099 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
    2100 }
    2101 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
    2102 }
    2103
    2104 /* checks for each GUB whether all pairs of its variables have a common clique */
    2105 for( i = 0; i < gubset->ngubconss; i++ )
    2106 {
    2107 int j;
    2108
    2109 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
    2110 {
    2111 int k;
    2112
    2113 /* get corresponding active problem variable */
    2114 var1 = vars[gubset->gubconss[i]->gubvars[j]];
    2115 var1negated = FALSE;
    2116 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
    2117
    2118 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
    2119 {
    2120 /* get corresponding active problem variable */
    2121 var2 = vars[gubset->gubconss[i]->gubvars[k]];
    2122 var2negated = FALSE;
    2123 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
    2124
    2125 if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
    2126 {
    2127 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
    2128 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
    2129 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
    2130 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
    2131 SCIPvarGetName(var1), k,
    2132 SCIPvarGetName(var2));
    2133 }
    2134
    2135 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
    2136 assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
    2137 }
    2138 }
    2139 }
    2140 SCIPdebugMsg(scip, " --> successful\n");
    2141
    2142 return SCIP_OKAY;
    2143}
    2144#endif
    2145
    2146/** calculates a partition of the given set of binary variables into cliques;
    2147 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
    2148 * were assigned to the same clique;
    2149 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
    2150 * the preceding variables was assigned to clique i-1;
    2151 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
    2152 * variable) and for the remaining variables, a partition with a small number of cliques is constructed
    2153 */
    2154
    2155static
    2157 SCIP*const scip, /**< SCIP data structure */
    2158 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
    2159 int const nvars, /**< number of variables in the clique */
    2160 int*const cliquepartition, /**< array of length nvars to store the clique partition */
    2161 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
    2162 SCIP_Real* solvals /**< solution values of all given binary variables */
    2163 )
    2164{
    2165 SCIP_VAR** tmpvars;
    2166 SCIP_VAR** cliquevars;
    2167 SCIP_Bool* cliquevalues;
    2168 SCIP_Bool* tmpvalues;
    2169 int* varseq;
    2170 int* sortkeys;
    2171 int ncliquevars;
    2172 int maxncliquevarscomp;
    2173 int nignorevars;
    2174 int nvarsused;
    2175 int i;
    2176
    2177 assert(scip != NULL);
    2178 assert(nvars == 0 || vars != NULL);
    2179 assert(nvars == 0 || cliquepartition != NULL);
    2180 assert(ncliques != NULL);
    2181
    2182 if( nvars == 0 )
    2183 {
    2184 *ncliques = 0;
    2185 return SCIP_OKAY;
    2186 }
    2187
    2188 /* allocate temporary memory for storing the variables of the current clique */
    2189 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
    2190 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
    2191 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
    2192 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
    2194 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
    2195
    2196 /* initialize the cliquepartition array with -1 */
    2197 /* initialize the tmpvalues array */
    2198 for( i = nvars - 1; i >= 0; --i )
    2199 {
    2200 tmpvalues[i] = TRUE;
    2201 cliquepartition[i] = -1;
    2202 }
    2203
    2204 /* get corresponding active problem variables */
    2205 SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
    2206
    2207 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
    2208 * by nondecreasing number of cliques the variables are in
    2209 */
    2210 nignorevars = 0;
    2211 nvarsused = 0;
    2212 for( i = 0; i < nvars; i++ )
    2213 {
    2214 if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
    2215 {
    2216 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
    2217 varseq[nvars-1-nignorevars] = i;
    2218 nignorevars++;
    2219 }
    2220 else
    2221 {
    2222 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
    2223 varseq[nvarsused] = i;
    2224 sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
    2225 nvarsused++;
    2226 }
    2227 }
    2228 assert(nvarsused + nignorevars == nvars);
    2229
    2230 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
    2231 SCIPsortIntInt(sortkeys, varseq, nvarsused);
    2232
    2233 maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
    2234
    2235 /* calculate the clique partition */
    2236 *ncliques = 0;
    2237 for( i = 0; i < nvars; ++i )
    2238 {
    2239 if( cliquepartition[varseq[i]] == -1 )
    2240 {
    2241 int j;
    2242
    2243 /* variable starts a new clique */
    2244 cliquepartition[varseq[i]] = *ncliques;
    2245 cliquevars[0] = tmpvars[varseq[i]];
    2246 cliquevalues[0] = tmpvalues[varseq[i]];
    2247 ncliquevars = 1;
    2248
    2249 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
    2250 * if the variable has LP value 1 we do not want it to be in nontrivial cliques
    2251 */
    2252 if( i < nvarsused && SCIPvarIsActive(tmpvars[varseq[i]]) )
    2253 {
    2254 /* greedily fill up the clique */
    2255 for( j = i + 1; j < nvarsused; ++j )
    2256 {
    2257 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
    2258 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
    2259 {
    2260 int k;
    2261
    2262 /* check if every variable in the actual clique is in clique with the new variable */
    2263 for( k = ncliquevars - 1; k >= 0; --k )
    2264 {
    2265 if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
    2266 cliquevalues[k], TRUE) )
    2267 break;
    2268 }
    2269
    2270 if( k == -1 )
    2271 {
    2272 /* put the variable into the same clique */
    2273 cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
    2274 cliquevars[ncliquevars] = tmpvars[varseq[j]];
    2275 cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
    2276 ++ncliquevars;
    2277 }
    2278 }
    2279 }
    2280 }
    2281
    2282 /* this clique is finished */
    2283 ++(*ncliques);
    2284 }
    2285 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
    2286
    2287 /* break if we reached the maximal number of comparisons */
    2288 if( i * nvars > maxncliquevarscomp )
    2289 break;
    2290 }
    2291 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
    2292 for( ; i < nvars; ++i )
    2293 {
    2294 if( cliquepartition[varseq[i]] == -1 )
    2295 {
    2296 cliquepartition[varseq[i]] = *ncliques;
    2297 ++(*ncliques);
    2298 }
    2299 }
    2300
    2301 /* free temporary memory */
    2302 SCIPfreeBufferArray(scip, &sortkeys);
    2303 SCIPfreeBufferArray(scip, &varseq);
    2304 SCIPfreeBufferArray(scip, &tmpvars);
    2305 SCIPfreeBufferArray(scip, &tmpvalues);
    2306 SCIPfreeBufferArray(scip, &cliquevalues);
    2307 SCIPfreeBufferArray(scip, &cliquevars);
    2308
    2309 return SCIP_OKAY;
    2310}
    2311
    2312/** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
    2313static
    2315 SCIP* scip, /**< SCIP data structure */
    2316 SCIP_GUBSET* gubset, /**< GUB set data structure */
    2317 SCIP_VAR** vars, /**< variables in the knapsack constraint */
    2318 SCIP_Real* solvals /**< solution values of all knapsack variables */
    2319 )
    2320{
    2321 int* cliquepartition;
    2322 int* gubfirstvar;
    2323 int ncliques;
    2324 int currentgubconsidx;
    2325 int newgubconsidx;
    2326 int cliqueidx;
    2327 int nvars;
    2328 int i;
    2329
    2330 assert(scip != NULL);
    2331 assert(gubset != NULL);
    2332 assert(vars != NULL);
    2333
    2334 nvars = gubset->nvars;
    2335 assert(nvars >= 0);
    2336
    2337 /* allocate temporary memory for clique partition */
    2338 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
    2339
    2340 /* compute sophisticated clique partition */
    2341 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
    2342
    2343 /* allocate temporary memory for GUB set data structure */
    2344 SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
    2345
    2346 /* translate GUB partition into GUB set data structure */
    2347 for( i = 0; i < ncliques; i++ )
    2348 {
    2349 /* initialize first variable for every GUB */
    2350 gubfirstvar[i] = -1;
    2351 }
    2352 /* move every knapsack variable into GUB defined by clique partition */
    2353 for( i = 0; i < nvars; i++ )
    2354 {
    2355 assert(cliquepartition[i] >= 0);
    2356
    2357 cliqueidx = cliquepartition[i];
    2358 currentgubconsidx = gubset->gubconssidx[i];
    2359 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
    2360
    2361 /* variable is first element in GUB constraint defined by clique partition */
    2362 if( gubfirstvar[cliqueidx] == -1 )
    2363 {
    2364 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
    2365 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
    2366 */
    2367 assert(gubset->gubvarsidx[i] == 0);
    2368 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
    2369
    2370 /* remember the first variable found for the current GUB */
    2371 gubfirstvar[cliqueidx] = i;
    2372 }
    2373 /* variable is additional element of GUB constraint defined by clique partition */
    2374 else
    2375 {
    2376 assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
    2377
    2378 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
    2379 * first variable of this GUB constraint
    2380 */
    2381 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
    2382 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
    2383 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
    2384
    2385 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
    2386 }
    2387 }
    2388
    2389#ifdef SCIP_DEBUG
    2390 /* prints GUB set data structure */
    2391 GUBsetPrint(scip, gubset, vars, solvals);
    2392#endif
    2393
    2394#ifndef NDEBUG
    2395 /* checks consistency of GUB set data structure */
    2396 SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
    2397#endif
    2398
    2399 /* free temporary memory */
    2400 SCIPfreeBufferArray(scip, &gubfirstvar);
    2401 SCIPfreeBufferArray(scip, &cliquepartition);
    2402
    2403 return SCIP_OKAY;
    2404}
    2405
    2406/** 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$
    2407 * 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
    2408 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
    2409 */
    2410static
    2412 SCIP* scip, /**< SCIP data structure */
    2413 SCIP_VAR** vars, /**< variables in knapsack constraint */
    2414 int nvars, /**< number of variables in knapsack constraint */
    2415 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2416 SCIP_Longint capacity, /**< capacity of knapsack */
    2417 SCIP_Real* solvals, /**< solution values of all problem variables */
    2418 int* covervars, /**< pointer to store cover variables */
    2419 int* noncovervars, /**< pointer to store noncover variables */
    2420 int* ncovervars, /**< pointer to store number of cover variables */
    2421 int* nnoncovervars, /**< pointer to store number of noncover variables */
    2422 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
    2423 SCIP_Bool* found, /**< pointer to store whether a cover was found */
    2424 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
    2425 int* ntightened, /**< pointer to store number of variables with tightened upper bound */
    2426 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
    2427 )
    2428{
    2429 SCIP_Longint* transweights;
    2430 SCIP_Real* transprofits;
    2431 SCIP_Longint transcapacity;
    2432 SCIP_Longint fixedonesweight;
    2433 SCIP_Longint itemsweight;
    2434 SCIP_Bool infeasible;
    2435 int* fixedones;
    2436 int* fixedzeros;
    2437 int* items;
    2438 int nfixedones;
    2439 int nfixedzeros;
    2440 int nitems;
    2441 int j;
    2442
    2443 assert(scip != NULL);
    2444 assert(vars != NULL);
    2445 assert(nvars > 0);
    2446 assert(weights != NULL);
    2447 assert(capacity >= 0);
    2448 assert(solvals != NULL);
    2449 assert(covervars != NULL);
    2450 assert(noncovervars != NULL);
    2451 assert(ncovervars != NULL);
    2452 assert(nnoncovervars != NULL);
    2453 assert(coverweight != NULL);
    2454 assert(found != NULL);
    2455 assert(ntightened != NULL);
    2456 assert(fractional != NULL);
    2457
    2458 SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
    2459
    2460 /* allocates temporary memory */
    2461 SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
    2462 SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
    2463 SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
    2464 SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
    2466
    2467 *found = FALSE;
    2468 *ncovervars = 0;
    2469 *nnoncovervars = 0;
    2470 *coverweight = 0;
    2471 *fractional = TRUE;
    2472
    2473 /* gets the following sets
    2474 * N_1 = {j in N : x*_j = 1} (fixedones),
    2475 * N_0 = {j in N : x*_j = 0} (fixedzeros) and
    2476 * N\‍(N_0 & N_1) (items),
    2477 * where x*_j is the solution value of variable x_j
    2478 */
    2479 nfixedones = 0;
    2480 nfixedzeros = 0;
    2481 nitems = 0;
    2482 fixedonesweight = 0;
    2483 itemsweight = 0;
    2484 *ntightened = 0;
    2485 for( j = 0; j < nvars; j++ )
    2486 {
    2487 assert(SCIPvarIsBinary(vars[j]));
    2488
    2489 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
    2490 if( weights[j] > capacity )
    2491 {
    2492 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
    2493 assert(!infeasible);
    2494 (*ntightened)++;
    2495 continue;
    2496 }
    2497
    2498 /* variable x_j has solution value one */
    2499 if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
    2500 {
    2501 fixedones[nfixedones] = j;
    2502 nfixedones++;
    2503 fixedonesweight += weights[j];
    2504 }
    2505 /* variable x_j has solution value zero */
    2506 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
    2507 {
    2508 fixedzeros[nfixedzeros] = j;
    2509 nfixedzeros++;
    2510 }
    2511 /* variable x_j has fractional solution value */
    2512 else
    2513 {
    2514 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
    2515 items[nitems] = j;
    2516 nitems++;
    2517 itemsweight += weights[j];
    2518 }
    2519 }
    2520 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
    2521
    2522 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
    2523 * the separation routine
    2524 */
    2525 assert(nitems >= 0);
    2526 if( nitems == 0 )
    2527 {
    2528 *fractional = FALSE;
    2529 goto TERMINATE;
    2530 }
    2531 assert(*fractional);
    2532
    2533 /* transforms the traditional separation problem (under consideration of the following fixing:
    2534 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
    2535 *
    2536 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
    2537 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
    2538 * z_j in {0,1}, j in N\‍(N_0 & N_1)
    2539 *
    2540 * to a knapsack problem in maximization form by complementing the variables
    2541 *
    2542 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) -
    2543 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
    2544 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
    2545 * z_j in {0,1}, j in N\‍(N_0 & N_1)
    2546 */
    2547
    2548 /* gets weight and profit of variables in transformed knapsack problem */
    2549 for( j = 0; j < nitems; j++ )
    2550 {
    2551 transweights[j] = weights[items[j]];
    2552 transprofits[j] = 1.0 - solvals[items[j]];
    2553 }
    2554 /* gets capacity of transformed knapsack problem */
    2555 transcapacity = fixedonesweight + itemsweight - capacity - 1;
    2556
    2557 /* if capacity of transformed knapsack problem is less than zero, there is no cover
    2558 * (when variables fixed to zero are not used)
    2559 */
    2560 if( transcapacity < 0 )
    2561 {
    2562 assert(!(*found));
    2563 goto TERMINATE;
    2564 }
    2565
    2566 if( modtransused )
    2567 {
    2568 /* transforms the modified separation problem (under consideration of the following fixing:
    2569 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
    2570 *
    2571 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
    2572 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
    2573 * z_j in {0,1}, j in N\‍(N_0 & N_1)
    2574 *
    2575 * to a knapsack problem in maximization form by complementing the variables
    2576 *
    2577 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j -
    2578 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
    2579 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
    2580 * z_j in {0,1}, j in N\‍(N_0 & N_1)
    2581 */
    2582
    2583 /* gets weight and profit of variables in modified transformed knapsack problem */
    2584 for( j = 0; j < nitems; j++ )
    2585 {
    2586 transprofits[j] *= weights[items[j]];
    2587 assert(SCIPisFeasPositive(scip, transprofits[j]));
    2588 }
    2589 }
    2590
    2591 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
    2592 * transformed knapsack problem using Dantzig's method and rounding down the solution.
    2593 * let z* be the solution, then
    2594 * j in C, if z*_j = 0 and
    2595 * i in N\C, if z*_j = 1.
    2596 */
    2597 SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
    2598 noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
    2599 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
    2600
    2601 /* constructs cover C (sum_{j in C} a_j > a_0) */
    2602 for( j = 0; j < *ncovervars; j++ )
    2603 {
    2604 (*coverweight) += weights[covervars[j]];
    2605 }
    2606
    2607 /* adds all variables from N_1 to C */
    2608 for( j = 0; j < nfixedones; j++ )
    2609 {
    2610 covervars[*ncovervars] = fixedones[j];
    2611 (*ncovervars)++;
    2612 (*coverweight) += weights[fixedones[j]];
    2613 }
    2614
    2615 /* adds all variables from N_0 to N\C */
    2616 for( j = 0; j < nfixedzeros; j++ )
    2617 {
    2618 noncovervars[*nnoncovervars] = fixedzeros[j];
    2619 (*nnoncovervars)++;
    2620 }
    2621 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
    2622 assert((*coverweight) > capacity);
    2623 *found = TRUE;
    2624
    2625 TERMINATE:
    2626 /* frees temporary memory */
    2627 SCIPfreeBufferArray(scip, &items);
    2628 SCIPfreeBufferArray(scip, &fixedzeros);
    2629 SCIPfreeBufferArray(scip, &fixedones);
    2630 SCIPfreeBufferArray(scip, &transprofits);
    2631 SCIPfreeBufferArray(scip, &transweights);
    2632
    2633 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
    2634
    2635 return SCIP_OKAY;
    2636}
    2637
    2638#ifndef NDEBUG
    2639/** checks if minweightidx is set correctly
    2640 */
    2641static
    2643 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2644 SCIP_Longint capacity, /**< capacity of knapsack */
    2645 int* covervars, /**< pointer to store cover variables */
    2646 int ncovervars, /**< pointer to store number of cover variables */
    2647 SCIP_Longint coverweight, /**< pointer to store weight of cover */
    2648 int minweightidx, /**< index of variable in cover variables with minimum weight */
    2649 int j /**< current index in cover variables */
    2650 )
    2651{
    2652 SCIP_Longint minweight;
    2653 int i;
    2654
    2655 assert(weights != NULL);
    2656 assert(covervars != NULL);
    2657 assert(ncovervars > 0);
    2658
    2659 minweight = weights[covervars[minweightidx]];
    2660
    2661 /* checks if all cover variables before index j have weight greater than minweight */
    2662 for( i = 0; i < j; i++ )
    2663 {
    2664 assert(weights[covervars[i]] > minweight);
    2665 if( weights[covervars[i]] <= minweight )
    2666 return FALSE;
    2667 }
    2668
    2669 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
    2670 for( i = 0; i < j; i++ )
    2671 {
    2672 assert(coverweight - weights[covervars[i]] <= capacity);
    2673 if( coverweight - weights[covervars[i]] > capacity )
    2674 return FALSE;
    2675 }
    2676 return TRUE;
    2677}
    2678#endif
    2679
    2680
    2681/** 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$,
    2682 * 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$
    2683 */
    2684static
    2686 SCIP* scip, /**< SCIP data structure */
    2687 SCIP_Real* solvals, /**< solution values of all problem variables */
    2688 int* covervars, /**< cover variables */
    2689 int ncovervars, /**< number of cover variables */
    2690 int* varsC1, /**< pointer to store variables in C1 */
    2691 int* varsC2, /**< pointer to store variables in C2 */
    2692 int* nvarsC1, /**< pointer to store number of variables in C1 */
    2693 int* nvarsC2 /**< pointer to store number of variables in C2 */
    2694 )
    2695{
    2696 int j;
    2697
    2698 assert(scip != NULL);
    2699 assert(ncovervars >= 0);
    2700 assert(solvals != NULL);
    2701 assert(covervars != NULL);
    2702 assert(varsC1 != NULL);
    2703 assert(varsC2 != NULL);
    2704 assert(nvarsC1 != NULL);
    2705 assert(nvarsC2 != NULL);
    2706
    2707 *nvarsC1 = 0;
    2708 *nvarsC2 = 0;
    2709 for( j = 0; j < ncovervars; j++ )
    2710 {
    2711 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
    2712
    2713 /* variable has solution value one */
    2714 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
    2715 {
    2716 varsC2[*nvarsC2] = covervars[j];
    2717 (*nvarsC2)++;
    2718 }
    2719 /* variable has solution value less than one */
    2720 else
    2721 {
    2722 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
    2723 varsC1[*nvarsC1] = covervars[j];
    2724 (*nvarsC1)++;
    2725 }
    2726 }
    2727 assert((*nvarsC1) + (*nvarsC2) == ncovervars);
    2728}
    2729
    2730/** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
    2731 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
    2732 */
    2733static
    2735 SCIP* scip, /**< SCIP data structure */
    2736 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2737 int* varsC1, /**< pointer to store variables in C1 */
    2738 int* varsC2, /**< pointer to store variables in C2 */
    2739 int* nvarsC1, /**< pointer to store number of variables in C1 */
    2740 int* nvarsC2 /**< pointer to store number of variables in C2 */
    2741 )
    2742{
    2743 SCIP_Real* sortkeysC2;
    2744 int j;
    2745
    2746 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
    2747 assert(*nvarsC2 > 0);
    2748
    2749 /* allocates temporary memory */
    2750 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
    2751
    2752 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
    2753 for( j = 0; j < *nvarsC2; j++ )
    2754 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
    2755 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
    2756
    2757 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
    2758 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
    2759 while( *nvarsC1 < 2 && *nvarsC2 > 0 )
    2760 {
    2761 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
    2762 (*nvarsC1)++;
    2763 (*nvarsC2)--;
    2764 }
    2765
    2766 /* frees temporary memory */
    2767 SCIPfreeBufferArray(scip, &sortkeysC2);
    2768
    2769 return SCIP_OKAY;
    2770}
    2771
    2772/** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
    2773static
    2775 SCIP* scip, /**< SCIP data structure */
    2776 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2777 int* varsC1, /**< pointer to store variables in C1 */
    2778 int* varsC2, /**< pointer to store variables in C2 */
    2779 int* nvarsC1, /**< pointer to store number of variables in C1 */
    2780 int* nvarsC2 /**< pointer to store number of variables in C2 */
    2781 )
    2782{
    2783 SCIP_Real* sortkeysC2;
    2784 int j;
    2785
    2786 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
    2787 assert(*nvarsC2 > 0);
    2788
    2789 /* allocates temporary memory */
    2790 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
    2791
    2792 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
    2793 for( j = 0; j < *nvarsC2; j++ )
    2794 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
    2795 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
    2796
    2797 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
    2798 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
    2799 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
    2800 (*nvarsC1)++;
    2801 (*nvarsC2)--;
    2802
    2803 /* frees temporary memory */
    2804 SCIPfreeBufferArray(scip, &sortkeysC2);
    2805
    2806 return SCIP_OKAY;
    2807}
    2808
    2809
    2810/** 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$
    2811 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
    2812 * \f$F = (N \setminus C) \setminus F\f$
    2813 */
    2814static
    2816 SCIP* scip, /**< SCIP data structure */
    2817 SCIP_Real* solvals, /**< solution values of all problem variables */
    2818 int* noncovervars, /**< noncover variables */
    2819 int nnoncovervars, /**< number of noncover variables */
    2820 int* varsF, /**< pointer to store variables in F */
    2821 int* varsR, /**< pointer to store variables in R */
    2822 int* nvarsF, /**< pointer to store number of variables in F */
    2823 int* nvarsR /**< pointer to store number of variables in R */
    2824 )
    2825{
    2826 int j;
    2827
    2828 assert(scip != NULL);
    2829 assert(nnoncovervars >= 0);
    2830 assert(solvals != NULL);
    2831 assert(noncovervars != NULL);
    2832 assert(varsF != NULL);
    2833 assert(varsR != NULL);
    2834 assert(nvarsF != NULL);
    2835 assert(nvarsR != NULL);
    2836
    2837 *nvarsF = 0;
    2838 *nvarsR = 0;
    2839
    2840 for( j = 0; j < nnoncovervars; j++ )
    2841 {
    2842 /* variable has solution value zero */
    2843 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
    2844 {
    2845 varsR[*nvarsR] = noncovervars[j];
    2846 (*nvarsR)++;
    2847 }
    2848 /* variable has solution value greater than zero */
    2849 else
    2850 {
    2851 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
    2852 varsF[*nvarsF] = noncovervars[j];
    2853 (*nvarsF)++;
    2854 }
    2855 }
    2856 assert((*nvarsF) + (*nvarsR) == nnoncovervars);
    2857}
    2858
    2859/** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
    2860 * lifting procedure
    2861 */
    2862static
    2864 SCIP* scip, /**< SCIP data structure */
    2865 SCIP_Real* solvals, /**< solution values of all problem variables */
    2866 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2867 int* varsF, /**< pointer to store variables in F */
    2868 int* varsC2, /**< pointer to store variables in C2 */
    2869 int* varsR, /**< pointer to store variables in R */
    2870 int nvarsF, /**< number of variables in F */
    2871 int nvarsC2, /**< number of variables in C2 */
    2872 int nvarsR /**< number of variables in R */
    2873 )
    2874{
    2875 SORTKEYPAIR** sortkeypairsF;
    2876 SORTKEYPAIR* sortkeypairsFstore;
    2877 SCIP_Real* sortkeysC2;
    2878 SCIP_Real* sortkeysR;
    2879 int j;
    2880
    2881 assert(scip != NULL);
    2882 assert(solvals != NULL);
    2883 assert(weights != NULL);
    2884 assert(varsF != NULL);
    2885 assert(varsC2 != NULL);
    2886 assert(varsR != NULL);
    2887 assert(nvarsF >= 0);
    2888 assert(nvarsC2 >= 0);
    2889 assert(nvarsR >= 0);
    2890
    2891 /* allocates temporary memory */
    2892 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
    2893 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
    2894 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
    2895 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
    2896
    2897 /* gets sorting key for variables in F corresponding to the following lifting sequence
    2898 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
    2899 * x*_1 >= x*_2 >= ... >= x*_|F|
    2900 * in case of equality uses
    2901 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
    2902 */
    2903 for( j = 0; j < nvarsF; j++ )
    2904 {
    2905 sortkeypairsF[j] = &(sortkeypairsFstore[j]);
    2906 sortkeypairsF[j]->key1 = solvals[varsF[j]];
    2907 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
    2908 }
    2909
    2910 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
    2911 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
    2912 */
    2913 for( j = 0; j < nvarsC2; j++ )
    2914 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
    2915
    2916 /* gets sorting key for variables in R corresponding to the following lifting sequence
    2917 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
    2918 */
    2919 for( j = 0; j < nvarsR; j++ )
    2920 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
    2921
    2922 /* sorts F, C2 and R */
    2923 if( nvarsF > 0 )
    2924 {
    2925 SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
    2926 }
    2927 if( nvarsC2 > 0 )
    2928 {
    2929 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
    2930 }
    2931 if( nvarsR > 0)
    2932 {
    2933 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
    2934 }
    2935
    2936 /* frees temporary memory */
    2937 SCIPfreeBufferArray(scip, &sortkeysR);
    2938 SCIPfreeBufferArray(scip, &sortkeysC2);
    2939 SCIPfreeBufferArray(scip, &sortkeypairsFstore);
    2940 SCIPfreeBufferArray(scip, &sortkeypairsF);
    2941
    2942 return SCIP_OKAY;
    2943}
    2944
    2945/** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
    2946 * for the sequential GUB wise lifting procedure
    2947 */
    2948static
    2950 SCIP* scip, /**< SCIP data structure */
    2951 SCIP_GUBSET* gubset, /**< GUB set data structure */
    2952 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
    2953 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    2954 int* varsC1, /**< variables in C1 */
    2955 int* varsC2, /**< variables in C2 */
    2956 int* varsF, /**< variables in F */
    2957 int* varsR, /**< variables in R */
    2958 int nvarsC1, /**< number of variables in C1 */
    2959 int nvarsC2, /**< number of variables in C2 */
    2960 int nvarsF, /**< number of variables in F */
    2961 int nvarsR, /**< number of variables in R */
    2962 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
    2963 int* gubconsGC2, /**< pointer to store GUBs in GC2 */
    2964 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
    2965 int* gubconsGR, /**< pointer to store GUBs in GR */
    2966 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
    2967 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
    2968 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
    2969 int* ngubconsGR, /**< pointer to store number of GUBs in GR */
    2970 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
    2971 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
    2972 )
    2973{
    2974 SORTKEYPAIR** sortkeypairsGFC1;
    2975 SORTKEYPAIR* sortkeypairsGFC1store;
    2976 SCIP_Real* sortkeysC1;
    2977 SCIP_Real* sortkeysC2;
    2978 SCIP_Real* sortkeysR;
    2979 int* nC1varsingubcons;
    2980 int var;
    2981 int gubconsidx;
    2982 int varidx;
    2983 int ngubconss;
    2984 int ngubconsGOC1;
    2985 int targetvar;
    2986#ifndef NDEBUG
    2987 int nvarsprocessed = 0;
    2988#endif
    2989 int i;
    2990 int j;
    2991
    2992#if GUBSPLITGNC1GUBS
    2993 SCIP_Bool gubconswithF;
    2994 int origngubconss;
    2995 origngubconss = gubset->ngubconss;
    2996#endif
    2997
    2998 assert(scip != NULL);
    2999 assert(gubset != NULL);
    3000 assert(solvals != NULL);
    3001 assert(weights != NULL);
    3002 assert(varsC1 != NULL);
    3003 assert(varsC2 != NULL);
    3004 assert(varsF != NULL);
    3005 assert(varsR != NULL);
    3006 assert(nvarsC1 > 0);
    3007 assert(nvarsC2 >= 0);
    3008 assert(nvarsF >= 0);
    3009 assert(nvarsR >= 0);
    3010 assert(gubconsGC1 != NULL);
    3011 assert(gubconsGC2 != NULL);
    3012 assert(gubconsGFC1 != NULL);
    3013 assert(gubconsGR != NULL);
    3014 assert(ngubconsGC1 != NULL);
    3015 assert(ngubconsGC2 != NULL);
    3016 assert(ngubconsGFC1 != NULL);
    3017 assert(ngubconsGR != NULL);
    3018 assert(maxgubvarssize != NULL);
    3019
    3020 ngubconss = gubset->ngubconss;
    3021 ngubconsGOC1 = 0;
    3022
    3023 /* GUBs are categorized into different types according to the variables in volved
    3024 * - GOC1: involves variables in C1 only -- no C2, R, F
    3025 * - GNC1: involves variables in C1 and F (and R) -- no C2
    3026 * - GF: involves variables in F (and R) only -- no C1, C2
    3027 * - GC2: involves variables in C2 only -- no C1, R, F
    3028 * - GR: involves variables in R only -- no C1, C2, F
    3029 * which requires splitting GUBs in case they include variable in F and R.
    3030 *
    3031 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
    3032 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
    3033 * - second ordering level is
    3034 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
    3035 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
    3036 * GR: non-increasing max{ a_k : k in GR_j}
    3037 *
    3038 * in additon, another GUB union, which is helpful for the lifting procedure, is formed
    3039 * - GC1: GUBs of category GOC1 and GNC1
    3040 * with second ordering level non-decreasing min{ a_k : k in GC1_j };
    3041 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
    3042 */
    3043
    3044 /* allocates temporary memory */
    3045 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
    3046 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
    3047 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
    3048
    3049 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
    3050 * - F: non-increasing x*_j and non-increasing a_j in case of equality
    3051 * - C2: non-increasing a_j
    3052 * - R: non-increasing a_j
    3053 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
    3054 */
    3055
    3056 /* gets sorting key for variables in C1 corresponding to the following ordering
    3057 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
    3058 */
    3059 for( j = 0; j < nvarsC1; j++ )
    3060 {
    3061 /* gets sortkeys */
    3062 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
    3063
    3064 /* update status of variable in its gub constraint */
    3065 gubconsidx = gubset->gubconssidx[varsC1[j]];
    3066 varidx = gubset->gubvarsidx[varsC1[j]];
    3067 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
    3068 }
    3069
    3070 /* gets sorting key for variables in F corresponding to the following ordering
    3071 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
    3072 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
    3073 * and updates status of each variable in F in GUB set data structure
    3074 */
    3075 for( j = 0; j < nvarsF; j++ )
    3076 {
    3077 /* update status of variable in its gub constraint */
    3078 gubconsidx = gubset->gubconssidx[varsF[j]];
    3079 varidx = gubset->gubvarsidx[varsF[j]];
    3080 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
    3081 }
    3082
    3083 /* gets sorting key for variables in C2 corresponding to the following ordering
    3084 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
    3085 * and updates status of each variable in F in GUB set data structure
    3086 */
    3087 for( j = 0; j < nvarsC2; j++ )
    3088 {
    3089 /* gets sortkeys */
    3090 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
    3091
    3092 /* update status of variable in its gub constraint */
    3093 gubconsidx = gubset->gubconssidx[varsC2[j]];
    3094 varidx = gubset->gubvarsidx[varsC2[j]];
    3095 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
    3096 }
    3097
    3098 /* gets sorting key for variables in R corresponding to the following ordering
    3099 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
    3100 * and updates status of each variable in F in GUB set data structure
    3101 */
    3102 for( j = 0; j < nvarsR; j++ )
    3103 {
    3104 /* gets sortkeys */
    3105 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
    3106
    3107 /* update status of variable in its gub constraint */
    3108 gubconsidx = gubset->gubconssidx[varsR[j]];
    3109 varidx = gubset->gubvarsidx[varsR[j]];
    3110 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
    3111 }
    3112
    3113 /* sorts C1, F, C2 and R */
    3114 assert(nvarsC1 > 0);
    3115 SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
    3116
    3117 if( nvarsC2 > 0 )
    3118 {
    3119 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
    3120 }
    3121 if( nvarsR > 0)
    3122 {
    3123 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
    3124 }
    3125
    3126 /* frees temporary memory */
    3127 SCIPfreeBufferArray(scip, &sortkeysR);
    3128 SCIPfreeBufferArray(scip, &sortkeysC2);
    3129 SCIPfreeBufferArray(scip, &sortkeysC1);
    3130
    3131 /* allocate and initialize temporary memory for sorting GUB constraints */
    3132 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
    3133 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
    3134 SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
    3135 BMSclearMemoryArray(nC1varsingubcons, ngubconss);
    3136 for( i = 0; i < ngubconss; i++)
    3137 {
    3138 sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
    3139 sortkeypairsGFC1[i]->key1 = 0.0;
    3140 sortkeypairsGFC1[i]->key2 = 0.0;
    3141 }
    3142 *ngubconsGC1 = 0;
    3143 *ngubconsGC2 = 0;
    3144 *ngubconsGFC1 = 0;
    3145 *ngubconsGR = 0;
    3146 *ngubconscapexceed = 0;
    3147 *maxgubvarssize = 0;
    3148
    3149#ifndef NDEBUG
    3150 for( i = 0; i < gubset->ngubconss; i++ )
    3151 assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
    3152#endif
    3153
    3154 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
    3155 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
    3156 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
    3157 * non-increasing number of variables in F, and
    3158 * non-increasing max{x*_k : k in GFC1_j} in case of equality
    3159 */
    3160 for( i = 0; i < nvarsC1; i++ )
    3161 {
    3162 int nvarsC1capexceed;
    3163
    3164 nvarsC1capexceed = 0;
    3165
    3166 var = varsC1[i];
    3167 gubconsidx = gubset->gubconssidx[var];
    3168 varidx = gubset->gubvarsidx[var];
    3169
    3170 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
    3171 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
    3172
    3173 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
    3174 * note that variables in C1 are already sorted by non-decreasing weigth
    3175 */
    3176 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
    3177 GUBsetSwapVars(scip, gubset, var, targetvar);
    3178 nC1varsingubcons[gubconsidx]++;
    3179
    3180 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
    3181 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
    3182 {
    3183 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
    3184 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    3185 continue;
    3186 }
    3187
    3188 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
    3189 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
    3190 */
    3191#if GUBSPLITGNC1GUBS
    3192 gubconswithF = FALSE;
    3193#endif
    3194 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
    3195 {
    3196 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
    3197
    3198 /* C1-variable: update number of C1/capacity exceeding variables */
    3199 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
    3200 {
    3201 nvarsC1capexceed++;
    3202#ifndef NDEBUG
    3203 nvarsprocessed++;
    3204#endif
    3205 }
    3206 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
    3207 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
    3208 {
    3209#if GUBSPLITGNC1GUBS
    3210 gubconswithF = TRUE;
    3211#endif
    3212 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
    3213
    3214 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
    3215 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
    3216 }
    3217 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
    3218 {
    3219 nvarsC1capexceed++;
    3220 }
    3221 else
    3222 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
    3223 }
    3224
    3225 /* update set of GC1 GUBs */
    3226 gubconsGC1[*ngubconsGC1] = gubconsidx;
    3227 (*ngubconsGC1)++;
    3228
    3229 /* update maximum size of all GUB constraints */
    3230 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
    3231 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
    3232
    3233 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
    3234 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
    3235 {
    3236 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
    3237 ngubconsGOC1++;
    3238 }
    3239 else
    3240 {
    3241#if GUBSPLITGNC1GUBS
    3242 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
    3243 if( !gubconswithF )
    3244 {
    3245 GUBVARSTATUS movevarstatus;
    3246
    3247 assert(gubset->ngubconss < gubset->nvars);
    3248
    3249 /* create a new GUB for GR part of splitting */
    3250 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
    3251 gubset->ngubconss++;
    3252 ngubconss = gubset->ngubconss;
    3253
    3254 /* fill GR with R variables in current GUB */
    3255 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
    3256 {
    3257 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
    3258 if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
    3259 {
    3260 assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
    3261 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
    3262 gubconsidx, ngubconss-1) );
    3263 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
    3264 movevarstatus;
    3265 }
    3266 }
    3267
    3268 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
    3269 ngubconsGOC1++;
    3270
    3272 gubconsGR[*ngubconsGR] = ngubconss-1;
    3273 (*ngubconsGR)++;
    3274 }
    3275 /* variables in C1, F, and maybe R: GNC1 GUB */
    3276 else
    3277 {
    3278 assert(gubconswithF);
    3279
    3280 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
    3281 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
    3282 (*ngubconsGFC1)++;
    3283 }
    3284#else
    3285 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
    3286 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
    3287 (*ngubconsGFC1)++;
    3288#endif
    3289 }
    3290 }
    3291
    3292 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
    3293 * are already sorted correctly
    3294 */
    3295 for( i = 0; i < nvarsC2; i++ )
    3296 {
    3297 var = varsC2[i];
    3298 gubconsidx = gubset->gubconssidx[var];
    3299 varidx = gubset->gubvarsidx[var];
    3300
    3301 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
    3302 assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
    3303 assert(varidx == 0);
    3304 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
    3305 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
    3306
    3307 /* set status of GC2 GUB */
    3308 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
    3309
    3310 /* update group of GC2 GUBs */
    3311 gubconsGC2[*ngubconsGC2] = gubconsidx;
    3312 (*ngubconsGC2)++;
    3313
    3314 /* update maximum size of all GUB constraints */
    3315 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
    3316 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
    3317
    3318#ifndef NDEBUG
    3319 nvarsprocessed++;
    3320#endif
    3321 }
    3322
    3323 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
    3324 * non-increasing number of variables in F, and
    3325 * non-increasing max{x*_k : k in GFC1_j} in case of equality
    3326 */
    3327 for( i = 0; i < nvarsF; i++ )
    3328 {
    3329 var = varsF[i];
    3330 gubconsidx = gubset->gubconssidx[var];
    3331 varidx = gubset->gubvarsidx[var];
    3332
    3333 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
    3334 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
    3335
    3336#ifndef NDEBUG
    3337 nvarsprocessed++;
    3338#endif
    3339
    3340 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
    3341 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
    3342 {
    3343 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
    3344 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    3345 continue;
    3346 }
    3347
    3348 /* set status of GF GUB */
    3349 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
    3350
    3351 /* update sorting key of corresponding GFC1 GUB */
    3352 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
    3353 {
    3354 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
    3355 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
    3356
    3357 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
    3358 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
    3359 {
    3360 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
    3361
    3362 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
    3363 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
    3364 }
    3365 }
    3366
    3367 /* update set of GFC1 GUBs */
    3368 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
    3369 (*ngubconsGFC1)++;
    3370
    3371 /* update maximum size of all GUB constraints */
    3372 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
    3373 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
    3374 }
    3375
    3376 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
    3377 * correctly
    3378 */
    3379 for( i = 0; i < nvarsR; i++ )
    3380 {
    3381 var = varsR[i];
    3382 gubconsidx = gubset->gubconssidx[var];
    3383 varidx = gubset->gubvarsidx[var];
    3384
    3385 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
    3386 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
    3387
    3388#ifndef NDEBUG
    3389 nvarsprocessed++;
    3390#endif
    3391
    3392 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
    3393 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
    3394 {
    3395 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
    3396 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
    3397 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    3398 continue;
    3399 }
    3400
    3401 /* set status of GR GUB */
    3402 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
    3403
    3404 /* update set of GR GUBs */
    3405 gubconsGR[*ngubconsGR] = gubconsidx;
    3406 (*ngubconsGR)++;
    3407
    3408 /* update maximum size of all GUB constraints */
    3409 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
    3410 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
    3411 }
    3412 assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
    3413
    3414 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
    3415 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
    3416 assert(*ngubconscapexceed >= 0);
    3417#ifndef NDEBUG
    3418 {
    3419 int check;
    3420
    3421 check = 0;
    3422
    3423 /* remaining not handled GUBs should only contain capacity exceeding variables */
    3424 for( i = 0; i < ngubconss; i++ )
    3425 {
    3426 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
    3427 check++;
    3428 }
    3429 assert(check == *ngubconscapexceed);
    3430 }
    3431#endif
    3432
    3433 /* sort GFCI GUBs according to computed sorting keys */
    3434 if( (*ngubconsGFC1) > 0 )
    3435 {
    3436 SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
    3437 }
    3438
    3439 /* free temporary memory */
    3440#if GUBSPLITGNC1GUBS
    3441 ngubconss = origngubconss;
    3442#endif
    3443 SCIPfreeBufferArray(scip, &nC1varsingubcons);
    3444 SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
    3445 SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
    3446
    3447 return SCIP_OKAY;
    3448}
    3449
    3450/** enlarges minweight table to at least the given length */
    3451static
    3453 SCIP* scip, /**< SCIP data structure */
    3454 SCIP_Longint** minweightsptr, /**< pointer to minweights table */
    3455 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
    3456 int* minweightssize, /**< pointer to current size of minweights table */
    3457 int newlen /**< new length of minweights table */
    3458 )
    3459{
    3460 int j;
    3461
    3462 assert(minweightsptr != NULL);
    3463 assert(*minweightsptr != NULL);
    3464 assert(minweightslen != NULL);
    3465 assert(*minweightslen >= 0);
    3466 assert(minweightssize != NULL);
    3467 assert(*minweightssize >= 0);
    3468
    3469 if( newlen > *minweightssize )
    3470 {
    3471 int newsize;
    3472
    3473 /* reallocate table memory */
    3474 newsize = SCIPcalcMemGrowSize(scip, newlen);
    3475 SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
    3476 *minweightssize = newsize;
    3477 }
    3478 assert(newlen <= *minweightssize);
    3479
    3480 /* initialize new elements */
    3481 for( j = *minweightslen; j < newlen; ++j )
    3482 (*minweightsptr)[j] = SCIP_LONGINT_MAX;
    3483 *minweightslen = newlen;
    3484
    3485 return SCIP_OKAY;
    3486}
    3487
    3488/** lifts given inequality
    3489 * sum_{j in M_1} x_j <= alpha_0
    3490 * valid for
    3491 * 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 }
    3492 * to a valid inequality
    3493 * 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
    3494 * <= alpha_0 + sum_{j in M_2} alpha_j
    3495 * for
    3496 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
    3497 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
    3498 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
    3499 * extended weight inequalities.
    3500 */
    3501static
    3503 SCIP* scip, /**< SCIP data structure */
    3504 SCIP_VAR** vars, /**< variables in knapsack constraint */
    3505 int nvars, /**< number of variables in knapsack constraint */
    3506 int ntightened, /**< number of variables with tightened upper bound */
    3507 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    3508 SCIP_Longint capacity, /**< capacity of knapsack */
    3509 SCIP_Real* solvals, /**< solution values of all problem variables */
    3510 int* varsM1, /**< variables in M_1 */
    3511 int* varsM2, /**< variables in M_2 */
    3512 int* varsF, /**< variables in F */
    3513 int* varsR, /**< variables in R */
    3514 int nvarsM1, /**< number of variables in M_1 */
    3515 int nvarsM2, /**< number of variables in M_2 */
    3516 int nvarsF, /**< number of variables in F */
    3517 int nvarsR, /**< number of variables in R */
    3518 int alpha0, /**< rights hand side of given valid inequality */
    3519 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
    3520 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
    3521 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
    3522 )
    3523{
    3524 SCIP_Longint* minweights;
    3525 SCIP_Real* sortkeys;
    3526 SCIP_Longint fixedonesweight;
    3527 int minweightssize;
    3528 int minweightslen;
    3529 int j;
    3530 int w;
    3531
    3532 assert(scip != NULL);
    3533 assert(vars != NULL);
    3534 assert(nvars >= 0);
    3535 assert(weights != NULL);
    3536 assert(capacity >= 0);
    3537 assert(solvals != NULL);
    3538 assert(varsM1 != NULL);
    3539 assert(varsM2 != NULL);
    3540 assert(varsF != NULL);
    3541 assert(varsR != NULL);
    3542 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
    3543 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
    3544 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
    3545 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
    3546 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
    3547 assert(alpha0 >= 0);
    3548 assert(liftcoefs != NULL);
    3549 assert(cutact != NULL);
    3550 assert(liftrhs != NULL);
    3551
    3552 /* allocates temporary memory */
    3553 minweightssize = nvarsM1 + 1;
    3554 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
    3555 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
    3556
    3557 /* initializes data structures */
    3558 BMSclearMemoryArray(liftcoefs, nvars);
    3559 *cutact = 0.0;
    3560
    3561 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
    3562 * and calculates activity of the current valid inequality
    3563 */
    3564 for( j = 0; j < nvarsM1; j++ )
    3565 {
    3566 assert(liftcoefs[varsM1[j]] == 0);
    3567 liftcoefs[varsM1[j]] = 1;
    3568 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
    3569 (*cutact) += solvals[varsM1[j]];
    3570 }
    3571
    3572 SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
    3573
    3574 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
    3575 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
    3576 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
    3577 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
    3578 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
    3579 */
    3580 minweights[0] = 0;
    3581 for( w = 1; w <= nvarsM1; w++ )
    3582 minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
    3583 minweightslen = nvarsM1 + 1;
    3584
    3585 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
    3586 fixedonesweight = 0;
    3587 for( j = 0; j < nvarsM2; j++ )
    3588 fixedonesweight += weights[varsM2[j]];
    3589 assert(fixedonesweight >= 0);
    3590
    3591 /* initializes right hand side of lifted valid inequality */
    3592 *liftrhs = alpha0;
    3593
    3594 /* sequentially up-lifts all variables in F: */
    3595 for( j = 0; j < nvarsF; j++ )
    3596 {
    3597 SCIP_Longint weight;
    3598 int liftvar;
    3599 int liftcoef;
    3600 int z;
    3601
    3602 liftvar = varsF[j];
    3603 weight = weights[liftvar];
    3604 assert(liftvar >= 0 && liftvar < nvars);
    3605 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
    3606 assert(weight > 0);
    3607
    3608 /* knapsack problem is infeasible:
    3609 * sets z = 0
    3610 */
    3611 if( capacity - fixedonesweight - weight < 0 )
    3612 {
    3613 z = 0;
    3614 }
    3615 /* knapsack problem is feasible:
    3616 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
    3617 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
    3618 */
    3619 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
    3620 {
    3621 z = *liftrhs;
    3622 }
    3623 /* knapsack problem is feasible:
    3624 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
    3625 */
    3626 else
    3627 {
    3628 int left;
    3629 int right;
    3630 int middle;
    3631
    3632 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
    3633 left = 0;
    3634 right = (*liftrhs) + 1;
    3635 while( left < right - 1 )
    3636 {
    3637 middle = (left + right) / 2;
    3638 assert(0 <= middle && middle < minweightslen);
    3639 if( minweights[middle] <= capacity - fixedonesweight - weight )
    3640 left = middle;
    3641 else
    3642 right = middle;
    3643 }
    3644 assert(left == right - 1);
    3645 assert(0 <= left && left < minweightslen);
    3646 assert(minweights[left] <= capacity - fixedonesweight - weight );
    3647 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
    3648
    3649 /* now z = left */
    3650 z = left;
    3651 assert(z <= *liftrhs);
    3652 }
    3653
    3654 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
    3655 liftcoef = (*liftrhs) - z;
    3656 liftcoefs[liftvar] = liftcoef;
    3657 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
    3658
    3659 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
    3660 if( liftcoef == 0 )
    3661 continue;
    3662
    3663 /* updates activity of current valid inequality */
    3664 (*cutact) += liftcoef * solvals[liftvar];
    3665
    3666 /* enlarges current minweight table:
    3667 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
    3668 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
    3669 * and sets minweights_i[w] = infinity for
    3670 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
    3671 */
    3672 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
    3673
    3674 /* updates minweight table: minweight_i+1[w] =
    3675 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
    3676 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
    3677 */
    3678 for( w = minweightslen - 1; w >= 0; w-- )
    3679 {
    3681 if( w < liftcoef )
    3682 {
    3683 min = MIN(minweights[w], weight);
    3684 minweights[w] = min;
    3685 }
    3686 else
    3687 {
    3688 assert(w >= liftcoef);
    3689 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
    3690 minweights[w] = min;
    3691 }
    3692 }
    3693 }
    3694 assert(minweights[0] == 0);
    3695
    3696 /* sequentially down-lifts all variables in M_2: */
    3697 for( j = 0; j < nvarsM2; j++ )
    3698 {
    3699 SCIP_Longint weight;
    3700 int liftvar;
    3701 int liftcoef;
    3702 int left;
    3703 int right;
    3704 int middle;
    3705 int z;
    3706
    3707 liftvar = varsM2[j];
    3708 weight = weights[liftvar];
    3709 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
    3710 assert(liftvar >= 0 && liftvar < nvars);
    3711 assert(weight > 0);
    3712
    3713 /* uses binary search to find
    3714 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
    3715 */
    3716 left = 0;
    3717 right = minweightslen;
    3718 while( left < right - 1 )
    3719 {
    3720 middle = (left + right) / 2;
    3721 assert(0 <= middle && middle < minweightslen);
    3722 if( minweights[middle] <= capacity - fixedonesweight + weight )
    3723 left = middle;
    3724 else
    3725 right = middle;
    3726 }
    3727 assert(left == right - 1);
    3728 assert(0 <= left && left < minweightslen);
    3729 assert(minweights[left] <= capacity - fixedonesweight + weight );
    3730 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
    3731
    3732 /* now z = left */
    3733 z = left;
    3734 assert(z >= *liftrhs);
    3735
    3736 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
    3737 liftcoef = z - (*liftrhs);
    3738 liftcoefs[liftvar] = liftcoef;
    3739 assert(liftcoef >= 0);
    3740
    3741 /* updates sum of weights of variables fixed to one */
    3742 fixedonesweight -= weight;
    3743
    3744 /* updates right-hand side of current valid inequality */
    3745 (*liftrhs) += liftcoef;
    3746 assert(*liftrhs >= alpha0);
    3747
    3748 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
    3749 if( liftcoef == 0 )
    3750 continue;
    3751
    3752 /* updates activity of current valid inequality */
    3753 (*cutact) += liftcoef * solvals[liftvar];
    3754
    3755 /* enlarges current minweight table:
    3756 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
    3757 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
    3758 * and sets minweights_i[w] = infinity for
    3759 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
    3760 */
    3761 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
    3762
    3763 /* updates minweight table: minweight_i+1[w] =
    3764 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
    3765 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
    3766 */
    3767 for( w = minweightslen - 1; w >= 0; w-- )
    3768 {
    3770 if( w < liftcoef )
    3771 {
    3772 min = MIN(minweights[w], weight);
    3773 minweights[w] = min;
    3774 }
    3775 else
    3776 {
    3777 assert(w >= liftcoef);
    3778 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
    3779 minweights[w] = min;
    3780 }
    3781 }
    3782 }
    3783 assert(fixedonesweight == 0);
    3784 assert(*liftrhs >= alpha0);
    3785
    3786 /* sequentially up-lifts all variables in R: */
    3787 for( j = 0; j < nvarsR; j++ )
    3788 {
    3789 SCIP_Longint weight;
    3790 int liftvar;
    3791 int liftcoef;
    3792 int z;
    3793
    3794 liftvar = varsR[j];
    3795 weight = weights[liftvar];
    3796 assert(liftvar >= 0 && liftvar < nvars);
    3797 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
    3798 assert(weight > 0);
    3799 assert(capacity - weight >= 0);
    3800 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
    3801
    3802 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
    3803 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
    3804 */
    3805 if( minweights[*liftrhs] <= capacity - weight )
    3806 {
    3807 z = *liftrhs;
    3808 }
    3809 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
    3810 */
    3811 else
    3812 {
    3813 int left;
    3814 int right;
    3815 int middle;
    3816
    3817 left = 0;
    3818 right = (*liftrhs) + 1;
    3819 while( left < right - 1)
    3820 {
    3821 middle = (left + right) / 2;
    3822 assert(0 <= middle && middle < minweightslen);
    3823 if( minweights[middle] <= capacity - weight )
    3824 left = middle;
    3825 else
    3826 right = middle;
    3827 }
    3828 assert(left == right - 1);
    3829 assert(0 <= left && left < minweightslen);
    3830 assert(minweights[left] <= capacity - weight );
    3831 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
    3832
    3833 /* now z = left */
    3834 z = left;
    3835 assert(z <= *liftrhs);
    3836 }
    3837
    3838 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
    3839 liftcoef = (*liftrhs) - z;
    3840 liftcoefs[liftvar] = liftcoef;
    3841 assert(liftcoef >= 0 && liftcoef <= *liftrhs);
    3842
    3843 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
    3844 if( liftcoef == 0 )
    3845 continue;
    3846
    3847 /* updates activity of current valid inequality */
    3848 (*cutact) += liftcoef * solvals[liftvar];
    3849
    3850 /* updates minweight table: minweight_i+1[w] =
    3851 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
    3852 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
    3853 */
    3854 for( w = *liftrhs; w >= 0; w-- )
    3855 {
    3857 if( w < liftcoef )
    3858 {
    3859 min = MIN(minweights[w], weight);
    3860 minweights[w] = min;
    3861 }
    3862 else
    3863 {
    3864 assert(w >= liftcoef);
    3865 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
    3866 minweights[w] = min;
    3867 }
    3868 }
    3869 }
    3870
    3871 /* frees temporary memory */
    3872 SCIPfreeBufferArray(scip, &sortkeys);
    3873 SCIPfreeBufferArray(scip, &minweights);
    3874
    3875 return SCIP_OKAY;
    3876}
    3877
    3878/** adds two minweight values in a safe way, i.e,, ensures no overflow */
    3879static
    3881 SCIP_Longint val1, /**< first value to add */
    3882 SCIP_Longint val2 /**< second value to add */
    3883 )
    3884{
    3885 assert(val1 >= 0);
    3886 assert(val2 >= 0);
    3887
    3888 if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
    3889 return SCIP_LONGINT_MAX;
    3890 else
    3891 {
    3892 assert(val1 <= SCIP_LONGINT_MAX - val2);
    3893 return (val1 + val2);
    3894 }
    3895}
    3896
    3897/** computes minweights table for lifting with GUBs by combining unfished and fished tables */
    3898static
    3900 SCIP_Longint* minweights, /**< minweight table to compute */
    3901 SCIP_Longint* finished, /**< given finished table */
    3902 SCIP_Longint* unfinished, /**< given unfinished table */
    3903 int minweightslen /**< length of minweight, finished, and unfinished tables */
    3904 )
    3905{
    3906 int w1;
    3907 int w2;
    3908
    3909 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
    3910 * note that finished and unfished arrays sorted by non-decreasing weight
    3911 */
    3912
    3913 /* initialize minweight with w2 = 0 */
    3914 w2 = 0;
    3915 assert(unfinished[w2] == 0);
    3916 for( w1 = 0; w1 < minweightslen; w1++ )
    3917 minweights[w1] = finished[w1];
    3918
    3919 /* consider w2 = 1, ..., minweightslen-1 */
    3920 for( w2 = 1; w2 < minweightslen; w2++ )
    3921 {
    3922 if( unfinished[w2] >= SCIP_LONGINT_MAX )
    3923 break;
    3924
    3925 for( w1 = 0; w1 < minweightslen - w2; w1++ )
    3926 {
    3927 SCIP_Longint temp;
    3928
    3929 temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
    3930 if( temp <= minweights[w1+w2] )
    3931 minweights[w1+w2] = temp;
    3932 }
    3933 }
    3934}
    3935
    3936/** lifts given inequality
    3937 * sum_{j in C_1} x_j <= alpha_0
    3938 * valid for
    3939 * 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;
    3940 * sum_{j in Q_i} x_j <= 1, forall i in I }
    3941 * to a valid inequality
    3942 * 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
    3943 * <= alpha_0 + sum_{j in C_2} alpha_j
    3944 * for
    3945 * 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 };
    3946 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
    3947 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
    3948 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
    3949 */
    3950static
    3952 SCIP* scip, /**< SCIP data structure */
    3953 SCIP_GUBSET* gubset, /**< GUB set data structure */
    3954 SCIP_VAR** vars, /**< variables in knapsack constraint */
    3955 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
    3956 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    3957 SCIP_Longint capacity, /**< capacity of knapsack */
    3958 SCIP_Real* solvals, /**< solution values of all knapsack variables */
    3959 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
    3960 int* gubconsGC2, /**< GUBs in GC2 */
    3961 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
    3962 int* gubconsGR, /**< GUBs in GR */
    3963 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
    3964 int ngubconsGC2, /**< number of GUBs in GC2 */
    3965 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
    3966 int ngubconsGR, /**< number of GUBs in GR */
    3967 int alpha0, /**< rights hand side of given valid inequality */
    3968 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
    3969 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
    3970 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
    3971 int maxgubvarssize /**< maximal size of GUB constraints */
    3972 )
    3973{
    3974 SCIP_Longint* minweights;
    3975 SCIP_Longint* finished;
    3976 SCIP_Longint* unfinished;
    3977 int* gubconsGOC1;
    3978 int* gubconsGNC1;
    3979 int* liftgubvars;
    3980 SCIP_Longint fixedonesweight;
    3981 SCIP_Longint weight;
    3982 SCIP_Longint weightdiff1;
    3983 SCIP_Longint weightdiff2;
    3985 int minweightssize;
    3986 int minweightslen;
    3987 int nvars;
    3988 int varidx;
    3989 int liftgubconsidx;
    3990 int liftvar;
    3991 int sumliftcoef;
    3992 int liftcoef;
    3993 int ngubconsGOC1;
    3994 int ngubconsGNC1;
    3995 int left;
    3996 int right;
    3997 int middle;
    3998 int nliftgubvars;
    3999 int tmplen;
    4000 int tmpsize;
    4001 int j;
    4002 int k;
    4003 int w;
    4004 int z;
    4005#ifndef NDEBUG
    4006 int ngubconss;
    4007 int nliftgubC1;
    4008
    4009 assert(gubset != NULL);
    4010 ngubconss = gubset->ngubconss;
    4011#else
    4012 assert(gubset != NULL);
    4013#endif
    4014
    4015 nvars = gubset->nvars;
    4016
    4017 assert(scip != NULL);
    4018 assert(vars != NULL);
    4019 assert(nvars >= 0);
    4020 assert(weights != NULL);
    4021 assert(capacity >= 0);
    4022 assert(solvals != NULL);
    4023 assert(gubconsGC1 != NULL);
    4024 assert(gubconsGC2 != NULL);
    4025 assert(gubconsGFC1 != NULL);
    4026 assert(gubconsGR != NULL);
    4027 assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
    4028 assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
    4029 assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
    4030 assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
    4031 assert(alpha0 >= 0);
    4032 assert(liftcoefs != NULL);
    4033 assert(cutact != NULL);
    4034 assert(liftrhs != NULL);
    4035
    4036 minweightssize = ngubconsGC1+1;
    4037
    4038 /* allocates temporary memory */
    4039 SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
    4040 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
    4041 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
    4042 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
    4043 SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
    4044 SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
    4045
    4046 /* initializes data structures */
    4047 BMSclearMemoryArray(liftcoefs, nvars);
    4048 *cutact = 0.0;
    4049
    4050 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
    4051 * valid inequality
    4052 */
    4053 ngubconsGOC1 = 0;
    4054 ngubconsGNC1 = 0;
    4055 for( j = 0; j < ngubconsGC1; j++ )
    4056 {
    4057 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
    4058 {
    4059 gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
    4060 ngubconsGOC1++;
    4061 }
    4062 else
    4063 {
    4064 assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    4065 gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
    4066 ngubconsGNC1++;
    4067 }
    4068 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
    4069 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4070 {
    4071 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
    4072 assert(varidx >= 0 && varidx < nvars);
    4073 assert(liftcoefs[varidx] == 0);
    4074
    4075 liftcoefs[varidx] = 1;
    4076 (*cutact) += solvals[varidx];
    4077 }
    4078 assert(k >= 1);
    4079 }
    4080 assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
    4081 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
    4082
    4083 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
    4084 * - finished_i[w] =
    4085 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
    4086 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
    4087 * sum_{j in Q_k} x_j <= 1
    4088 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
    4089 * - unfinished_i[w] =
    4090 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
    4091 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
    4092 * sum_{j in Q_k} x_j <= 1
    4093 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
    4094 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
    4095 */
    4096
    4097 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
    4098 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
    4099 * 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
    4100 * comes from the first variable in the GUB
    4101 */
    4102 assert(ngubconsGOC1 <= ngubconsGC1);
    4103 finished[0] = 0;
    4104 for( w = 1; w <= ngubconsGOC1; w++ )
    4105 {
    4106 liftgubconsidx = gubconsGOC1[w-1];
    4107
    4108 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
    4109 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
    4110
    4111 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
    4112
    4113 assert(varidx >= 0 && varidx < nvars);
    4114 assert(liftcoefs[varidx] == 1);
    4115
    4116 min = weights[varidx];
    4117 finished[w] = finished[w-1] + min;
    4118
    4119#ifndef NDEBUG
    4120 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
    4121 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4122 {
    4123 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4124 assert(varidx >= 0 && varidx < nvars);
    4125 assert(liftcoefs[varidx] == 1);
    4126 assert(weights[varidx] >= min);
    4127 }
    4128#endif
    4129 }
    4130 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
    4131 finished[w] = SCIP_LONGINT_MAX;
    4132
    4133 /* initialize unfinished table; note that variables in GNC1 GUBs
    4134 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
    4135 * 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
    4136 * comes from the first variable in the GUB
    4137 */
    4138 assert(ngubconsGNC1 <= ngubconsGC1);
    4139 unfinished[0] = 0;
    4140 for( w = 1; w <= ngubconsGNC1; w++ )
    4141 {
    4142 liftgubconsidx = gubconsGNC1[w-1];
    4143
    4144 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    4145 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
    4146
    4147 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
    4148
    4149 assert(varidx >= 0 && varidx < nvars);
    4150 assert(liftcoefs[varidx] == 1);
    4151
    4152 min = weights[varidx];
    4153 unfinished[w] = unfinished[w-1] + min;
    4154
    4155#ifndef NDEBUG
    4156 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
    4157 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4158 {
    4159 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4160 assert(varidx >= 0 && varidx < nvars);
    4161 assert(liftcoefs[varidx] == 1);
    4162 assert(weights[varidx] >= min );
    4163 }
    4164#endif
    4165 }
    4166 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
    4167 unfinished[w] = SCIP_LONGINT_MAX;
    4168
    4169 /* initialize minweights table; note that variables in GC1 GUBs
    4170 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
    4171 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
    4172 * consuming) because is it has to be build using weights from C1 only.
    4173 */
    4174 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
    4175 minweights[0] = 0;
    4176 for( w = 1; w <= ngubconsGC1; w++ )
    4177 {
    4178 liftgubconsidx = gubconsGC1[w-1];
    4179
    4180 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
    4181 || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    4182 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
    4183
    4184 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
    4185
    4186 assert(varidx >= 0 && varidx < nvars);
    4187 assert(liftcoefs[varidx] == 1);
    4188
    4189 min = weights[varidx];
    4190 minweights[w] = minweights[w-1] + min;
    4191
    4192#ifndef NDEBUG
    4193 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
    4194 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4195 {
    4196 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4197 assert(varidx >= 0 && varidx < nvars);
    4198 assert(liftcoefs[varidx] == 1);
    4199 assert(weights[varidx] >= min);
    4200 }
    4201#endif
    4202 }
    4203 minweightslen = ngubconsGC1 + 1;
    4204
    4205 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
    4206 fixedonesweight = 0;
    4207 for( j = 0; j < ngubconsGC2; j++ )
    4208 {
    4209 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
    4210
    4211 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
    4212 assert(varidx >= 0 && varidx < nvars);
    4213 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
    4214
    4215 fixedonesweight += weights[varidx];
    4216 }
    4217 assert(fixedonesweight >= 0);
    4218
    4219 /* initializes right hand side of lifted valid inequality */
    4220 *liftrhs = alpha0;
    4221
    4222 /* sequentially up-lifts all variables in GFC1 GUBs */
    4223 for( j = 0; j < ngubconsGFC1; j++ )
    4224 {
    4225 liftgubconsidx = gubconsGFC1[j];
    4226 assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
    4227
    4228 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
    4229 * compute minweight table via updated unfinished table and aleady upto date finished table;
    4230 */
    4231 k = 0;
    4232 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
    4233 {
    4234 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
    4235 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
    4236 assert(ngubconsGNC1 > 0);
    4237
    4238 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
    4239 * are considered for the lifting, i.e., not capacity exceeding
    4240 */
    4241 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
    4242 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
    4243 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4244 assert(k >= 1);
    4245
    4246 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
    4247 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
    4248 */
    4249 weight = weights[liftgubvars[0]];
    4250
    4251 weightdiff2 = unfinished[ngubconsGNC1] - weight;
    4252 unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
    4253 for( w = ngubconsGNC1-1; w >= 1; w-- )
    4254 {
    4255 weightdiff1 = weightdiff2;
    4256 weightdiff2 = unfinished[w] - weight;
    4257
    4258 if( unfinished[w] < weightdiff1 )
    4259 unfinished[w] = weightdiff1;
    4260 else
    4261 break;
    4262 }
    4263 ngubconsGNC1--;
    4264
    4265 /* computes minweights table by combining unfished and fished tables */
    4266 computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
    4267 assert(minweights[0] == 0);
    4268 }
    4269 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
    4270 * are therefore not in the unfinished table
    4271 */
    4272 else
    4273 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
    4274
    4275#ifndef NDEBUG
    4276 nliftgubC1 = k;
    4277#endif
    4278 nliftgubvars = k;
    4279 sumliftcoef = 0;
    4280
    4281 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
    4282 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
    4283 {
    4284 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
    4285 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
    4286 {
    4287 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4288 weight = weights[liftvar];
    4289 assert(weight > 0);
    4290 assert(liftvar >= 0 && liftvar < nvars);
    4291 assert(capacity - weight >= 0);
    4292
    4293 /* put variable into array of variables in GUB that are considered for the lifting,
    4294 * i.e., not capacity exceeding
    4295 */
    4296 liftgubvars[nliftgubvars] = liftvar;
    4297 nliftgubvars++;
    4298
    4299 /* knapsack problem is infeasible:
    4300 * sets z = 0
    4301 */
    4302 if( capacity - fixedonesweight - weight < 0 )
    4303 {
    4304 z = 0;
    4305 }
    4306 /* knapsack problem is feasible:
    4307 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
    4308 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
    4309 */
    4310 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
    4311 {
    4312 z = *liftrhs;
    4313 }
    4314 /* knapsack problem is feasible:
    4315 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
    4316 */
    4317 else
    4318 {
    4319 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
    4320 left = 0;
    4321 right = (*liftrhs) + 1;
    4322 while( left < right - 1 )
    4323 {
    4324 middle = (left + right) / 2;
    4325 assert(0 <= middle && middle < minweightslen);
    4326 if( minweights[middle] <= capacity - fixedonesweight - weight )
    4327 left = middle;
    4328 else
    4329 right = middle;
    4330 }
    4331 assert(left == right - 1);
    4332 assert(0 <= left && left < minweightslen);
    4333 assert(minweights[left] <= capacity - fixedonesweight - weight);
    4334 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
    4335
    4336 /* now z = left */
    4337 z = left;
    4338 assert(z <= *liftrhs);
    4339 }
    4340
    4341 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
    4342 liftcoef = (*liftrhs) - z;
    4343 liftcoefs[liftvar] = liftcoef;
    4344 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
    4345
    4346 /* updates activity of current valid inequality */
    4347 (*cutact) += liftcoef * solvals[liftvar];
    4348
    4349 /* updates sum of all lifting coefficients in GUB */
    4350 sumliftcoef += liftcoefs[liftvar];
    4351 }
    4352 else
    4353 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
    4354 }
    4355 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
    4356 assert(nliftgubvars > nliftgubC1);
    4357
    4358 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
    4359 * and finished and minweight table can be updated easily as only C1 variables need to be considered;
    4360 * not needed for GF GUBs
    4361 */
    4362 if( sumliftcoef == 0 )
    4363 {
    4364 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
    4365 {
    4366 weight = weights[liftgubvars[0]];
    4367 /* update finished table and minweights table by applying special case of
    4368 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
    4369 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
    4370 */
    4371 for( w = minweightslen-1; w >= 1; w-- )
    4372 {
    4373 SCIP_Longint tmpval;
    4374
    4375 tmpval = safeAddMinweightsGUB(finished[w-1], weight);
    4376 finished[w] = MIN(finished[w], tmpval);
    4377
    4378 tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
    4379 minweights[w] = MIN(minweights[w], tmpval);
    4380 }
    4381 }
    4382 else
    4383 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
    4384
    4385 continue;
    4386 }
    4387
    4388 /* enlarges current minweights tables(finished, unfinished, minweights):
    4389 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
    4390 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
    4391 * and sets minweights_i[w] = infinity for
    4392 * 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
    4393 */
    4394 tmplen = minweightslen; /* will be updated in enlargeMinweights() */
    4395 tmpsize = minweightssize;
    4396 SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
    4397 tmplen = minweightslen;
    4398 tmpsize = minweightssize;
    4399 SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
    4400 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
    4401
    4402 /* update finished table and minweight table;
    4403 * note that instead of computing minweight table from updated finished and updated unfinished table again
    4404 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
    4405 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
    4406 * not needed because only finished table changed at this point and the change was "adding" one weight)
    4407 *
    4408 * update formular for minweight table is: minweight_i+1[w] =
    4409 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
    4410 * formular for finished table has the same pattern.
    4411 */
    4412 for( w = minweightslen-1; w >= 0; w-- )
    4413 {
    4414 SCIP_Longint minminweight;
    4415 SCIP_Longint minfinished;
    4416
    4417 for( k = 0; k < nliftgubvars; k++ )
    4418 {
    4419 liftcoef = liftcoefs[liftgubvars[k]];
    4420 weight = weights[liftgubvars[k]];
    4421
    4422 if( w < liftcoef )
    4423 {
    4424 minfinished = MIN(finished[w], weight);
    4425 minminweight = MIN(minweights[w], weight);
    4426
    4427 finished[w] = minfinished;
    4428 minweights[w] = minminweight;
    4429 }
    4430 else
    4431 {
    4432 SCIP_Longint tmpval;
    4433
    4434 assert(w >= liftcoef);
    4435
    4436 tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
    4437 minfinished = MIN(finished[w], tmpval);
    4438
    4439 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
    4440 minminweight = MIN(minweights[w], tmpval);
    4441
    4442 finished[w] = minfinished;
    4443 minweights[w] = minminweight;
    4444 }
    4445 }
    4446 }
    4447 assert(minweights[0] == 0);
    4448 }
    4449 assert(ngubconsGNC1 == 0);
    4450
    4451 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
    4452 * therefore, only work with minweight table from here on
    4453 */
    4454
    4455 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
    4456 for( j = 0; j < ngubconsGC2; j++ )
    4457 {
    4458 liftgubconsidx = gubconsGC2[j];
    4459
    4460 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
    4461 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
    4462 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
    4463 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
    4464
    4465 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
    4466 weight = weights[liftvar];
    4467
    4468 assert(liftvar >= 0 && liftvar < nvars);
    4469 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
    4470 assert(weight > 0);
    4471
    4472 /* uses binary search to find
    4473 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
    4474 */
    4475 left = 0;
    4476 right = minweightslen;
    4477 while( left < right - 1 )
    4478 {
    4479 middle = (left + right) / 2;
    4480 assert(0 <= middle && middle < minweightslen);
    4481 if( minweights[middle] <= capacity - fixedonesweight + weight )
    4482 left = middle;
    4483 else
    4484 right = middle;
    4485 }
    4486 assert(left == right - 1);
    4487 assert(0 <= left && left < minweightslen);
    4488 assert(minweights[left] <= capacity - fixedonesweight + weight);
    4489 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
    4490
    4491 /* now z = left */
    4492 z = left;
    4493 assert(z >= *liftrhs);
    4494
    4495 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
    4496 liftcoef = z - (*liftrhs);
    4497 liftcoefs[liftvar] = liftcoef;
    4498 assert(liftcoef >= 0);
    4499
    4500 /* updates sum of weights of variables fixed to one */
    4501 fixedonesweight -= weight;
    4502
    4503 /* updates right-hand side of current valid inequality */
    4504 (*liftrhs) += liftcoef;
    4505 assert(*liftrhs >= alpha0);
    4506
    4507 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
    4508 if( liftcoef == 0 )
    4509 continue;
    4510
    4511 /* updates activity of current valid inequality */
    4512 (*cutact) += liftcoef * solvals[liftvar];
    4513
    4514 /* enlarges current minweight table:
    4515 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
    4516 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
    4517 * and sets minweights_i[w] = infinity for
    4518 * 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
    4519 */
    4520 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
    4521
    4522 /* updates minweight table: minweight_i+1[w] =
    4523 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
    4524 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
    4525 */
    4526 for( w = minweightslen - 1; w >= 0; w-- )
    4527 {
    4528 if( w < liftcoef )
    4529 {
    4530 min = MIN(minweights[w], weight);
    4531 minweights[w] = min;
    4532 }
    4533 else
    4534 {
    4535 SCIP_Longint tmpval;
    4536
    4537 assert(w >= liftcoef);
    4538
    4539 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
    4540 min = MIN(minweights[w], tmpval);
    4541 minweights[w] = min;
    4542 }
    4543 }
    4544 }
    4545 assert(fixedonesweight == 0);
    4546 assert(*liftrhs >= alpha0);
    4547
    4548 /* sequentially up-lifts variables in GUB constraints in GR GUBs */
    4549 for( j = 0; j < ngubconsGR; j++ )
    4550 {
    4551 liftgubconsidx = gubconsGR[j];
    4552
    4553 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
    4554 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
    4555
    4556 sumliftcoef = 0;
    4557 nliftgubvars = 0;
    4558 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
    4559 {
    4560 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
    4561 {
    4562 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
    4563 weight = weights[liftvar];
    4564 assert(weight > 0);
    4565 assert(liftvar >= 0 && liftvar < nvars);
    4566 assert(capacity - weight >= 0);
    4567 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
    4568
    4569 /* put variable into array of variables in GUB that are considered for the lifting,
    4570 * i.e., not capacity exceeding
    4571 */
    4572 liftgubvars[nliftgubvars] = liftvar;
    4573 nliftgubvars++;
    4574
    4575 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
    4576 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
    4577 */
    4578 if( minweights[*liftrhs] <= capacity - weight )
    4579 {
    4580 z = *liftrhs;
    4581 }
    4582 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
    4583 */
    4584 else
    4585 {
    4586 left = 0;
    4587 right = (*liftrhs) + 1;
    4588 while( left < right - 1 )
    4589 {
    4590 middle = (left + right) / 2;
    4591 assert(0 <= middle && middle < minweightslen);
    4592 if( minweights[middle] <= capacity - weight )
    4593 left = middle;
    4594 else
    4595 right = middle;
    4596 }
    4597 assert(left == right - 1);
    4598 assert(0 <= left && left < minweightslen);
    4599 assert(minweights[left] <= capacity - weight);
    4600 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
    4601
    4602 /* now z = left */
    4603 z = left;
    4604 assert(z <= *liftrhs);
    4605 }
    4606 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
    4607 liftcoef = (*liftrhs) - z;
    4608 liftcoefs[liftvar] = liftcoef;
    4609 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
    4610
    4611 /* updates activity of current valid inequality */
    4612 (*cutact) += liftcoef * solvals[liftvar];
    4613
    4614 /* updates sum of all lifting coefficients in GUB */
    4615 sumliftcoef += liftcoefs[liftvar];
    4616 }
    4617 else
    4618 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
    4619 }
    4620 assert(nliftgubvars >= 1); /* at least one variable is in R */
    4621
    4622 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
    4623 if( sumliftcoef == 0 )
    4624 continue;
    4625
    4626 /* updates minweight table: minweight_i+1[w] =
    4627 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
    4628 */
    4629 for( w = *liftrhs; w >= 0; w-- )
    4630 {
    4631 for( k = 0; k < nliftgubvars; k++ )
    4632 {
    4633 liftcoef = liftcoefs[liftgubvars[k]];
    4634 weight = weights[liftgubvars[k]];
    4635
    4636 if( w < liftcoef )
    4637 {
    4638 min = MIN(minweights[w], weight);
    4639 minweights[w] = min;
    4640 }
    4641 else
    4642 {
    4643 SCIP_Longint tmpval;
    4644
    4645 assert(w >= liftcoef);
    4646
    4647 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
    4648 min = MIN(minweights[w], tmpval);
    4649 minweights[w] = min;
    4650 }
    4651 }
    4652 }
    4653 assert(minweights[0] == 0);
    4654 }
    4655
    4656 /* frees temporary memory */
    4657 SCIPfreeBufferArray(scip, &minweights);
    4658 SCIPfreeBufferArray(scip, &finished);
    4659 SCIPfreeBufferArray(scip, &unfinished);
    4660 SCIPfreeBufferArray(scip, &liftgubvars);
    4661 SCIPfreeBufferArray(scip, &gubconsGOC1 );
    4662 SCIPfreeBufferArray(scip, &gubconsGNC1);
    4663
    4664 return SCIP_OKAY;
    4665}
    4666
    4667/** lifts given minimal cover inequality
    4668 * \f[
    4669 * \sum_{j \in C} x_j \leq |C| - 1
    4670 * \f]
    4671 * valid for
    4672 * \f[
    4673 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
    4674 * \f]
    4675 * to a valid inequality
    4676 * \f[
    4677 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
    4678 * \f]
    4679 * for
    4680 * \f[
    4681 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
    4682 * \f]
    4683 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
    4684 */
    4685static
    4687 SCIP* scip, /**< SCIP data structure */
    4688 SCIP_VAR** vars, /**< variables in knapsack constraint */
    4689 int nvars, /**< number of variables in knapsack constraint */
    4690 int ntightened, /**< number of variables with tightened upper bound */
    4691 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    4692 SCIP_Longint capacity, /**< capacity of knapsack */
    4693 SCIP_Real* solvals, /**< solution values of all problem variables */
    4694 int* covervars, /**< cover variables */
    4695 int* noncovervars, /**< noncover variables */
    4696 int ncovervars, /**< number of cover variables */
    4697 int nnoncovervars, /**< number of noncover variables */
    4698 SCIP_Longint coverweight, /**< weight of cover */
    4699 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
    4700 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
    4701 )
    4702{
    4703 SCIP_Longint* maxweightsums;
    4704 SCIP_Longint* intervalends;
    4705 SCIP_Longint* rhos;
    4706 SCIP_Real* sortkeys;
    4707 SCIP_Longint lambda;
    4708 int j;
    4709 int h;
    4710
    4711 assert(scip != NULL);
    4712 assert(vars != NULL);
    4713 assert(nvars >= 0);
    4714 assert(weights != NULL);
    4715 assert(capacity >= 0);
    4716 assert(solvals != NULL);
    4717 assert(covervars != NULL);
    4718 assert(noncovervars != NULL);
    4719 assert(ncovervars > 0 && ncovervars <= nvars);
    4720 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
    4721 assert(ncovervars + nnoncovervars == nvars - ntightened);
    4722 assert(liftcoefs != NULL);
    4723 assert(cutact != NULL);
    4724
    4725 /* allocates temporary memory */
    4726 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
    4727 SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
    4728 SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
    4729 SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
    4730
    4731 /* initializes data structures */
    4732 BMSclearMemoryArray(liftcoefs, nvars);
    4733 *cutact = 0.0;
    4734
    4735 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
    4736 * and calculates activity of current valid inequality
    4737 */
    4738 for( j = 0; j < ncovervars; j++ )
    4739 {
    4740 assert(liftcoefs[covervars[j]] == 0.0);
    4741 liftcoefs[covervars[j]] = 1.0;
    4742 sortkeys[j] = (SCIP_Real) weights[covervars[j]];
    4743 (*cutact) += solvals[covervars[j]];
    4744 }
    4745 SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
    4746
    4747 /* calculates weight excess of cover C */
    4748 lambda = coverweight - capacity;
    4749 assert(lambda > 0);
    4750
    4751 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
    4752 maxweightsums[0] = 0;
    4753 for( h = 1; h <= ncovervars; h++ )
    4754 {
    4755 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
    4756 intervalends[h-1] = maxweightsums[h] - lambda;
    4757 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
    4758 }
    4759
    4760 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
    4761 for( j = 0; j < nnoncovervars; j++ )
    4762 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
    4763 SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
    4764
    4765 /* calculates lifting coefficient for all variables in N\C */
    4766 h = 0;
    4767 for( j = 0; j < nnoncovervars; j++ )
    4768 {
    4769 int liftvar;
    4770 SCIP_Longint weight;
    4771 SCIP_Real liftcoef;
    4772
    4773 liftvar = noncovervars[j];
    4774 weight = weights[liftvar];
    4775
    4776 while( intervalends[h] < weight )
    4777 h++;
    4778
    4779 if( h == 0 )
    4780 liftcoef = h;
    4781 else
    4782 {
    4783 if( weight <= intervalends[h-1] + rhos[h] )
    4784 {
    4785 SCIP_Real tmp1;
    4786 SCIP_Real tmp2;
    4787 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
    4788 tmp2 = (SCIP_Real) rhos[1];
    4789 liftcoef = h - ( tmp1 / tmp2 );
    4790 }
    4791 else
    4792 liftcoef = h;
    4793 }
    4794
    4795 /* sets lifting coefficient */
    4796 assert(liftcoefs[liftvar] == 0.0);
    4797 liftcoefs[liftvar] = liftcoef;
    4798
    4799 /* updates activity of current valid inequality */
    4800 (*cutact) += liftcoef * solvals[liftvar];
    4801 }
    4802
    4803 /* frees temporary memory */
    4804 SCIPfreeBufferArray(scip, &rhos);
    4805 SCIPfreeBufferArray(scip, &intervalends);
    4806 SCIPfreeBufferArray(scip, &maxweightsums);
    4807 SCIPfreeBufferArray(scip, &sortkeys);
    4808
    4809 return SCIP_OKAY;
    4810}
    4811
    4812
    4813/** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
    4814 * given knapsack problem
    4815*/
    4816static
    4818 SCIP* scip, /**< SCIP data structure */
    4819 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
    4820 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    4821 SCIP_VAR** vars, /**< variables in knapsack constraint */
    4822 int nvars, /**< number of variables in knapsack constraint */
    4823 int ntightened, /**< number of variables with tightened upper bound */
    4824 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    4825 SCIP_Longint capacity, /**< capacity of knapsack */
    4826 SCIP_Real* solvals, /**< solution values of all problem variables */
    4827 int* mincovervars, /**< mincover variables */
    4828 int* nonmincovervars, /**< nonmincover variables */
    4829 int nmincovervars, /**< number of mincover variables */
    4830 int nnonmincovervars, /**< number of nonmincover variables */
    4831 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    4832 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
    4833 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
    4834 int* ncuts /**< pointer to add up the number of found cuts */
    4835 )
    4836{
    4837 int* varsC1;
    4838 int* varsC2;
    4839 int* varsF;
    4840 int* varsR;
    4841 int nvarsC1;
    4842 int nvarsC2;
    4843 int nvarsF;
    4844 int nvarsR;
    4845 SCIP_Real cutact;
    4846 int* liftcoefs;
    4847 int liftrhs;
    4848
    4849 assert( cutoff != NULL );
    4850 *cutoff = FALSE;
    4851
    4852 /* allocates temporary memory */
    4857 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
    4858
    4859 /* 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
    4860 * as follows
    4861 * C_2 = { j in C : x*_j = 1 } and
    4862 * C_1 = C\C_2
    4863 */
    4864 getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
    4865 assert(nvarsC1 + nvarsC2 == nmincovervars);
    4866 assert(nmincovervars > 0);
    4867 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
    4868
    4869 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
    4870 if( nvarsC1 < 2 && nvarsC2 > 0)
    4871 {
    4872 SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
    4873 assert(nvarsC1 >= 1);
    4874 }
    4875 assert(nvarsC2 == 0 || nvarsC1 >= 1);
    4876
    4877 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
    4878 * R = { j in N\C : x*_j = 0 } and
    4879 * F = (N\C)\F
    4880 */
    4881 getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
    4882 assert(nvarsF + nvarsR == nnonmincovervars);
    4883 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
    4884
    4885 /* lift cuts without GUB information */
    4886 if( gubset == NULL )
    4887 {
    4888 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
    4889 * lifting procedure
    4890 */
    4891 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
    4892
    4893 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
    4894 *
    4895 * 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 }
    4896 *
    4897 * 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
    4898 *
    4899 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
    4900 *
    4901 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
    4902 * up-lifting for the variables in R according to the second level lifting sequence
    4903 */
    4904 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
    4905 varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
    4906 }
    4907 /* lift cuts with GUB information */
    4908 else
    4909 {
    4910 int* gubconsGC1;
    4911 int* gubconsGC2;
    4912 int* gubconsGFC1;
    4913 int* gubconsGR;
    4914 int ngubconsGC1;
    4915 int ngubconsGC2;
    4916 int ngubconsGFC1;
    4917 int ngubconsGR;
    4918 int ngubconss;
    4919 int nconstightened;
    4920 int maxgubvarssize;
    4921
    4922 assert(nvars == gubset->nvars);
    4923
    4924 ngubconsGC1 = 0;
    4925 ngubconsGC2 = 0;
    4926 ngubconsGFC1 = 0;
    4927 ngubconsGR = 0;
    4928 ngubconss = gubset->ngubconss;
    4929 nconstightened = 0;
    4930 maxgubvarssize = 0;
    4931
    4932 /* allocates temporary memory */
    4933 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
    4934 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
    4935 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
    4937
    4938 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
    4939 * the GUBs for the sequential GUB wise lifting procedure
    4940 */
    4941 SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
    4942 nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
    4943 &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
    4944
    4945 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
    4946 *
    4947 * 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,
    4948 * sum_{j in Q_i} x_j <= 1, forall i in I }
    4949 *
    4950 * 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
    4951 *
    4952 * 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 },
    4953 *
    4954 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
    4955 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
    4956 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
    4957 */
    4958 SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
    4959 gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
    4960 MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
    4961
    4962 /* frees temporary memory */
    4963 SCIPfreeBufferArray(scip, &gubconsGR);
    4964 SCIPfreeBufferArray(scip, &gubconsGFC1);
    4965 SCIPfreeBufferArray(scip, &gubconsGC2);
    4966 SCIPfreeBufferArray(scip, &gubconsGC1);
    4967 }
    4968
    4969 /* checks if lifting yielded a violated cut */
    4970 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
    4971 {
    4972 SCIP_ROW* row;
    4973 char name[SCIP_MAXSTRLEN];
    4974 int j;
    4975
    4976 /* creates LP row */
    4977 assert( cons == NULL || sepa == NULL );
    4978 if ( cons != NULL )
    4979 {
    4981 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
    4982 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
    4983 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
    4984 }
    4985 else if ( sepa != NULL )
    4986 {
    4987 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
    4988 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
    4989 }
    4990 else
    4991 {
    4992 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
    4994 }
    4995
    4996 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
    4998 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
    4999 for( j = 0; j < nvarsC1; j++ )
    5000 {
    5001 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
    5002 }
    5003 for( j = 0; j < nvarsC2; j++ )
    5004 {
    5005 if( liftcoefs[varsC2[j]] > 0 )
    5006 {
    5007 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
    5008 }
    5009 }
    5010 for( j = 0; j < nvarsF; j++ )
    5011 {
    5012 if( liftcoefs[varsF[j]] > 0 )
    5013 {
    5014 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
    5015 }
    5016 }
    5017 for( j = 0; j < nvarsR; j++ )
    5018 {
    5019 if( liftcoefs[varsR[j]] > 0 )
    5020 {
    5021 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
    5022 }
    5023 }
    5025
    5026 /* checks if cut is violated enough */
    5027 if( SCIPisCutEfficacious(scip, sol, row) )
    5028 {
    5029 if( cons != NULL )
    5030 {
    5032 }
    5033 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    5034 (*ncuts)++;
    5035 }
    5036 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    5037 }
    5038
    5039 /* frees temporary memory */
    5040 SCIPfreeBufferArray(scip, &liftcoefs);
    5041 SCIPfreeBufferArray(scip, &varsR);
    5042 SCIPfreeBufferArray(scip, &varsF);
    5043 SCIPfreeBufferArray(scip, &varsC2);
    5044 SCIPfreeBufferArray(scip, &varsC1);
    5045
    5046 return SCIP_OKAY;
    5047}
    5048
    5049/** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
    5050static
    5052 SCIP* scip, /**< SCIP data structure */
    5053 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
    5054 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5055 SCIP_VAR** vars, /**< variables in knapsack constraint */
    5056 int nvars, /**< number of variables in knapsack constraint */
    5057 int ntightened, /**< number of variables with tightened upper bound */
    5058 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5059 SCIP_Longint capacity, /**< capacity of knapsack */
    5060 SCIP_Real* solvals, /**< solution values of all problem variables */
    5061 int* feassetvars, /**< variables in feasible set */
    5062 int* nonfeassetvars, /**< variables not in feasible set */
    5063 int nfeassetvars, /**< number of variables in feasible set */
    5064 int nnonfeassetvars, /**< number of variables not in feasible set */
    5065 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    5066 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    5067 int* ncuts /**< pointer to add up the number of found cuts */
    5068 )
    5069{
    5070 int* varsT1;
    5071 int* varsT2;
    5072 int* varsF;
    5073 int* varsR;
    5074 int* liftcoefs;
    5075 SCIP_Real cutact;
    5076 int nvarsT1;
    5077 int nvarsT2;
    5078 int nvarsF;
    5079 int nvarsR;
    5080 int liftrhs;
    5081 int j;
    5082
    5083 assert( cutoff != NULL );
    5084 *cutoff = FALSE;
    5085
    5086 /* allocates temporary memory */
    5091 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
    5092
    5093 /* 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
    5094 * as follows
    5095 * T_2 = { j in T : x*_j = 1 } and
    5096 * T_1 = T\T_2
    5097 */
    5098 getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
    5099 assert(nvarsT1 + nvarsT2 == nfeassetvars);
    5100
    5101 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
    5102 if( nvarsT1 == 0 && nvarsT2 > 0)
    5103 {
    5104 SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
    5105 assert(nvarsT1 == 1);
    5106 }
    5107 assert(nvarsT2 == 0 || nvarsT1 > 0);
    5108
    5109 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
    5110 * R = { j in N\T : x*_j = 0 } and
    5111 * F = (N\T)\F
    5112 */
    5113 getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
    5114 assert(nvarsF + nvarsR == nnonfeassetvars);
    5115 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
    5116
    5117 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
    5118 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
    5119 * is included in the sorting routine)
    5120 */
    5121 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
    5122
    5123 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
    5124 *
    5125 * 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 }
    5126 *
    5127 * 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
    5128 *
    5129 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
    5130 *
    5131 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
    5132 * up-lifting for the variabels in R according to the second level lifting sequence
    5133 */
    5134 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
    5135 nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
    5136
    5137 /* checks if lifting yielded a violated cut */
    5138 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
    5139 {
    5140 SCIP_ROW* row;
    5141 char name[SCIP_MAXSTRLEN];
    5142
    5143 /* creates LP row */
    5144 assert( cons == NULL || sepa == NULL );
    5145 if( cons != NULL )
    5146 {
    5149 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
    5150 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
    5151 }
    5152 else if ( sepa != NULL )
    5153 {
    5154 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
    5155 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
    5156 }
    5157 else
    5158 {
    5159 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
    5161 }
    5162
    5163 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
    5165 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
    5166 for( j = 0; j < nvarsT1; j++ )
    5167 {
    5168 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
    5169 }
    5170 for( j = 0; j < nvarsT2; j++ )
    5171 {
    5172 if( liftcoefs[varsT2[j]] > 0 )
    5173 {
    5174 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
    5175 }
    5176 }
    5177 for( j = 0; j < nvarsF; j++ )
    5178 {
    5179 if( liftcoefs[varsF[j]] > 0 )
    5180 {
    5181 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
    5182 }
    5183 }
    5184 for( j = 0; j < nvarsR; j++ )
    5185 {
    5186 if( liftcoefs[varsR[j]] > 0 )
    5187 {
    5188 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
    5189 }
    5190 }
    5192
    5193 /* checks if cut is violated enough */
    5194 if( SCIPisCutEfficacious(scip, sol, row) )
    5195 {
    5196 if( cons != NULL )
    5197 {
    5199 }
    5200 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    5201 (*ncuts)++;
    5202 }
    5203 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    5204 }
    5205
    5206 /* frees temporary memory */
    5207 SCIPfreeBufferArray(scip, &liftcoefs);
    5208 SCIPfreeBufferArray(scip, &varsR);
    5209 SCIPfreeBufferArray(scip, &varsF);
    5210 SCIPfreeBufferArray(scip, &varsT2);
    5211 SCIPfreeBufferArray(scip, &varsT1);
    5212
    5213 return SCIP_OKAY;
    5214}
    5215
    5216/** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
    5217static
    5219 SCIP* scip, /**< SCIP data structure */
    5220 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
    5221 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5222 SCIP_VAR** vars, /**< variables in knapsack constraint */
    5223 int nvars, /**< number of variables in knapsack constraint */
    5224 int ntightened, /**< number of variables with tightened upper bound */
    5225 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5226 SCIP_Longint capacity, /**< capacity of knapsack */
    5227 SCIP_Real* solvals, /**< solution values of all problem variables */
    5228 int* mincovervars, /**< mincover variables */
    5229 int* nonmincovervars, /**< nonmincover variables */
    5230 int nmincovervars, /**< number of mincover variables */
    5231 int nnonmincovervars, /**< number of nonmincover variables */
    5232 SCIP_Longint mincoverweight, /**< weight of minimal cover */
    5233 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    5234 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    5235 int* ncuts /**< pointer to add up the number of found cuts */
    5236 )
    5237{
    5238 SCIP_Real* realliftcoefs;
    5239 SCIP_Real cutact;
    5240 int liftrhs;
    5241
    5242 assert( cutoff != NULL );
    5243 *cutoff = FALSE;
    5244 cutact = 0.0;
    5245
    5246 /* allocates temporary memory */
    5247 SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
    5248
    5249 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
    5250 *
    5251 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
    5252 *
    5253 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
    5254 *
    5255 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
    5256 *
    5257 * uses superadditive up-lifting for the variables in N\C.
    5258 */
    5259 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
    5260 nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
    5261 liftrhs = nmincovervars - 1;
    5262
    5263 /* checks if lifting yielded a violated cut */
    5264 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
    5265 {
    5266 SCIP_ROW* row;
    5267 char name[SCIP_MAXSTRLEN];
    5268 int j;
    5269
    5270 /* creates LP row */
    5271 assert( cons == NULL || sepa == NULL );
    5272 if ( cons != NULL )
    5273 {
    5276 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
    5277 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
    5278 }
    5279 else if ( sepa != NULL )
    5280 {
    5281 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
    5282 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
    5283 }
    5284 else
    5285 {
    5286 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
    5288 }
    5289
    5290 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
    5292 assert(nmincovervars + nnonmincovervars == nvars - ntightened);
    5293 for( j = 0; j < nmincovervars; j++ )
    5294 {
    5295 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
    5296 }
    5297 for( j = 0; j < nnonmincovervars; j++ )
    5298 {
    5299 assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
    5300 if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
    5301 {
    5302 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
    5303 }
    5304 }
    5306
    5307 /* checks if cut is violated enough */
    5308 if( SCIPisCutEfficacious(scip, sol, row) )
    5309 {
    5310 if( cons != NULL )
    5311 {
    5313 }
    5314 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
    5315 (*ncuts)++;
    5316 }
    5317 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    5318 }
    5319
    5320 /* frees temporary memory */
    5321 SCIPfreeBufferArray(scip, &realliftcoefs);
    5322
    5323 return SCIP_OKAY;
    5324}
    5325
    5326/** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
    5327 * 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
    5328 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
    5329 * note that all variables with x*_j = 1 will be removed last
    5330 */
    5331static
    5333 SCIP* scip, /**< SCIP data structure */
    5334 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5335 SCIP_Longint capacity, /**< capacity of knapsack */
    5336 SCIP_Real* solvals, /**< solution values of all problem variables */
    5337 int* covervars, /**< pointer to store cover variables */
    5338 int* noncovervars, /**< pointer to store noncover variables */
    5339 int* ncovervars, /**< pointer to store number of cover variables */
    5340 int* nnoncovervars, /**< pointer to store number of noncover variables */
    5341 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
    5342 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
    5343 )
    5344{
    5345 SORTKEYPAIR** sortkeypairs;
    5346 SORTKEYPAIR** sortkeypairssorted;
    5347 SCIP_Longint minweight;
    5348 int nsortkeypairs;
    5349 int minweightidx;
    5350 int j;
    5351 int k;
    5352
    5353 assert(scip != NULL);
    5354 assert(covervars != NULL);
    5355 assert(noncovervars != NULL);
    5356 assert(ncovervars != NULL);
    5357 assert(*ncovervars > 0);
    5358 assert(nnoncovervars != NULL);
    5359 assert(*nnoncovervars >= 0);
    5360 assert(coverweight != NULL);
    5361 assert(*coverweight > 0);
    5362 assert(*coverweight > capacity);
    5363
    5364 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
    5365 * order */
    5366 nsortkeypairs = *ncovervars;
    5367 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
    5368 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
    5369
    5370 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
    5371 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
    5372 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
    5373 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
    5374 */
    5375 assert(*ncovervars == nsortkeypairs);
    5376 if( modtransused )
    5377 {
    5378 for( j = 0; j < *ncovervars; j++ )
    5379 {
    5380 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
    5381 sortkeypairssorted[j] = sortkeypairs[j];
    5382
    5383 sortkeypairs[j]->key1 = solvals[covervars[j]];
    5384 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
    5385 }
    5386 }
    5387 else
    5388 {
    5389 for( j = 0; j < *ncovervars; j++ )
    5390 {
    5391 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
    5392 sortkeypairssorted[j] = sortkeypairs[j];
    5393
    5394 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
    5395 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
    5396 }
    5397 }
    5398 SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
    5399
    5400 /* gets j' with a_j' = min{ a_j : j in C } */
    5401 minweightidx = 0;
    5402 minweight = weights[covervars[minweightidx]];
    5403 for( j = 1; j < *ncovervars; j++ )
    5404 {
    5405 if( weights[covervars[j]] <= minweight )
    5406 {
    5407 minweightidx = j;
    5408 minweight = weights[covervars[minweightidx]];
    5409 }
    5410 }
    5411 assert(minweightidx >= 0 && minweightidx < *ncovervars);
    5412 assert(minweight > 0 && minweight <= *coverweight);
    5413
    5414 j = 0;
    5415 /* removes variables from C until the remaining variables form a minimal cover */
    5416 while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
    5417 {
    5418 assert(minweightidx >= j);
    5419 assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
    5420
    5421 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
    5422 if( (*coverweight) - weights[covervars[j]] <= capacity )
    5423 {
    5424 ++j;
    5425 continue;
    5426 }
    5427
    5428 /* adds j to N\C */
    5429 noncovervars[*nnoncovervars] = covervars[j];
    5430 (*nnoncovervars)++;
    5431
    5432 /* removes j from C */
    5433 (*coverweight) -= weights[covervars[j]];
    5434 for( k = j; k < (*ncovervars) - 1; k++ )
    5435 covervars[k] = covervars[k+1];
    5436 (*ncovervars)--;
    5437
    5438 /* updates j' with a_j' = min{ a_j : j in C } */
    5439 if( j == minweightidx )
    5440 {
    5441 minweightidx = 0;
    5442 minweight = weights[covervars[minweightidx]];
    5443 for( k = 1; k < *ncovervars; k++ )
    5444 {
    5445 if( weights[covervars[k]] <= minweight )
    5446 {
    5447 minweightidx = k;
    5448 minweight = weights[covervars[minweightidx]];
    5449 }
    5450 }
    5451 assert(minweight > 0 && minweight <= *coverweight);
    5452 assert(minweightidx >= 0 && minweightidx < *ncovervars);
    5453 }
    5454 else
    5455 {
    5456 assert(minweightidx > j);
    5457 minweightidx--;
    5458 }
    5459 /* j needs to stay the same */
    5460 }
    5461 assert((*coverweight) > capacity);
    5462 assert((*coverweight) - minweight <= capacity);
    5463
    5464 /* frees temporary memory */
    5465 for( j = nsortkeypairs-1; j >= 0; j-- )
    5466 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
    5467 SCIPfreeBufferArray(scip, &sortkeypairssorted);
    5468 SCIPfreeBufferArray(scip, &sortkeypairs);
    5469
    5470 return SCIP_OKAY;
    5471}
    5472
    5473/** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
    5474 * they were chosen to be in C_init:
    5475 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
    5476 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
    5477 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
    5478 * and all subsequent feasible sets.
    5479 */
    5480static
    5482 SCIP* scip, /**< SCIP data structure */
    5483 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
    5484 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5485 SCIP_VAR** vars, /**< variables in knapsack constraint */
    5486 int nvars, /**< number of variables in knapsack constraint */
    5487 int ntightened, /**< number of variables with tightened upper bound */
    5488 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5489 SCIP_Longint capacity, /**< capacity of knapsack */
    5490 SCIP_Real* solvals, /**< solution values of all problem variables */
    5491 int* covervars, /**< pointer to store cover variables */
    5492 int* noncovervars, /**< pointer to store noncover variables */
    5493 int* ncovervars, /**< pointer to store number of cover variables */
    5494 int* nnoncovervars, /**< pointer to store number of noncover variables */
    5495 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
    5496 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
    5497 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    5498 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    5499 int* ncuts /**< pointer to add up the number of found cuts */
    5500 )
    5501{
    5502 SCIP_Real* sortkeys;
    5503 int j;
    5504 int k;
    5505
    5506 assert(scip != NULL);
    5507 assert(covervars != NULL);
    5508 assert(noncovervars != NULL);
    5509 assert(ncovervars != NULL);
    5510 assert(*ncovervars > 0);
    5511 assert(nnoncovervars != NULL);
    5512 assert(*nnoncovervars >= 0);
    5513 assert(coverweight != NULL);
    5514 assert(*coverweight > 0);
    5515 assert(*coverweight > capacity);
    5516 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
    5517 assert(cutoff != NULL);
    5518
    5519 *cutoff = FALSE;
    5520
    5521 /* allocates temporary memory */
    5522 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
    5523
    5524 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
    5525 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
    5526 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
    5527 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
    5528 */
    5529 if( modtransused )
    5530 {
    5531 for( j = 0; j < *ncovervars; j++ )
    5532 {
    5533 sortkeys[j] = solvals[covervars[j]];
    5534 assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
    5535 }
    5536 }
    5537 else
    5538 {
    5539 for( j = 0; j < *ncovervars; j++ )
    5540 {
    5541 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
    5542 assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
    5543 }
    5544 }
    5545 SCIPsortRealInt(sortkeys, covervars, *ncovervars);
    5546
    5547 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
    5548 * in addition to an extended weight inequality this gives cardinality inequalities */
    5549 while( *ncovervars >= 2 )
    5550 {
    5551 /* adds first element of C_init to N\C_init */
    5552 noncovervars[*nnoncovervars] = covervars[0];
    5553 (*nnoncovervars)++;
    5554
    5555 /* removes first element from C_init */
    5556 (*coverweight) -= weights[covervars[0]];
    5557 for( k = 0; k < (*ncovervars) - 1; k++ )
    5558 covervars[k] = covervars[k+1];
    5559 (*ncovervars)--;
    5560
    5561 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
    5562 if( (*coverweight) <= capacity )
    5563 {
    5564 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
    5565 covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
    5566 }
    5567
    5568 /* stop if cover is too large */
    5569 if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
    5570 break;
    5571 }
    5572
    5573 /* frees temporary memory */
    5574 SCIPfreeBufferArray(scip, &sortkeys);
    5575
    5576 return SCIP_OKAY;
    5577}
    5578
    5579/** separates different classes of valid inequalities for the 0-1 knapsack problem */
    5581 SCIP* scip, /**< SCIP data structure */
    5582 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
    5583 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5584 SCIP_VAR** vars, /**< variables in knapsack constraint */
    5585 int nvars, /**< number of variables in knapsack constraint */
    5586 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
    5587 SCIP_Longint capacity, /**< capacity of knapsack */
    5588 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
    5589 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
    5590 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
    5591 int* ncuts /**< pointer to add up the number of found cuts */
    5592 )
    5593{
    5594 SCIP_Real* solvals;
    5595 int* covervars;
    5596 int* noncovervars;
    5597 SCIP_Bool coverfound;
    5598 SCIP_Bool fractional;
    5599 SCIP_Bool modtransused;
    5600 SCIP_Longint coverweight;
    5601 int ncovervars;
    5602 int nnoncovervars;
    5603 int ntightened;
    5604
    5605 assert(scip != NULL);
    5606 assert(capacity >= 0);
    5607 assert(cutoff != NULL);
    5608 assert(ncuts != NULL);
    5609
    5610 *cutoff = FALSE;
    5611
    5612 if( nvars == 0 )
    5613 return SCIP_OKAY;
    5614
    5615 assert(vars != NULL);
    5616 assert(nvars > 0);
    5617 assert(weights != NULL);
    5618
    5619 /* increase age of constraint (age is reset to zero, if a cut was found) */
    5620 if( cons != NULL )
    5621 {
    5622 SCIP_CALL( SCIPincConsAge(scip, cons) );
    5623 }
    5624
    5625 /* allocates temporary memory */
    5627 SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
    5628 SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
    5629
    5630 /* gets solution values of all problem variables */
    5631 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
    5632
    5633#ifdef SCIP_DEBUG
    5634 {
    5635 int i;
    5636
    5637 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
    5638 cons == NULL ? "-" : SCIPconsGetName(cons));
    5639 for( i = 0; i < nvars; ++i )
    5640 {
    5641 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
    5642 }
    5643 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
    5644 }
    5645#endif
    5646
    5647 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
    5648 */
    5649 if( usegubs )
    5650 {
    5651 SCIP_GUBSET* gubset;
    5652
    5653 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
    5654
    5655 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
    5656 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
    5657
    5658 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
    5659 SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
    5660 assert(gubset->ngubconss <= nvars);
    5661
    5662 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
    5663 * MODIFIED transformed separation problem and taking into account the following fixing:
    5664 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
    5665 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
    5666 * if one exists
    5667 */
    5668 modtransused = TRUE;
    5669 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5670 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
    5671
    5672 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
    5673
    5674 /* if x* is not fractional we stop the separation routine */
    5675 if( !fractional )
    5676 {
    5677 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
    5678
    5679 /* frees memory for GUB set data structure */
    5680 GUBsetFree(scip, &gubset);
    5681
    5682 goto TERMINATE;
    5683 }
    5684
    5685 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
    5686 if( coverfound )
    5687 {
    5688 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
    5689 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
    5690 */
    5691 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5692 &nnoncovervars, &coverweight, modtransused) );
    5693
    5694 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
    5695 if( gubset->ngubconss < nvars )
    5696 {
    5697 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
    5698 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
    5699 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
    5700 }
    5701 else
    5702 {
    5703 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
    5704 * GUB information
    5705 */
    5706 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
    5707 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
    5708 }
    5709 }
    5710
    5711 /* frees memory for GUB set data structure */
    5712 GUBsetFree(scip, &gubset);
    5713 }
    5714 else
    5715 {
    5716 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
    5717 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
    5718 */
    5719
    5720 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
    5721 * MODIFIED transformed separation problem and taking into account the following fixing:
    5722 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
    5723 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
    5724 * if one exists
    5725 */
    5726 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
    5727 modtransused = TRUE;
    5728 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5729 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
    5730 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
    5731
    5732 /* if x* is not fractional we stop the separation routine */
    5733 if( !fractional )
    5734 goto TERMINATE;
    5735
    5736 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
    5737 if( coverfound )
    5738 {
    5739 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
    5740 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
    5741 */
    5742 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5743 &nnoncovervars, &coverweight, modtransused) );
    5744
    5745 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
    5746 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
    5747 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
    5748
    5749 if( USESUPADDLIFT ) /*lint !e506 !e774*/
    5750 {
    5751 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
    5752 /* separates lifted minimal cover inequalities using superadditive up-lifting */
    5753 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
    5754 solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
    5755 }
    5756 }
    5757 }
    5758
    5759 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
    5760 if ( ! (*cutoff) )
    5761 {
    5762 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
    5763 * transformed separation problem and taking into account the following fixing:
    5764 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
    5765 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
    5766 * if one exists
    5767 */
    5768 SCIPdebugMsg(scip, "separate LEWI cuts:\n");
    5769 modtransused = FALSE;
    5770 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
    5771 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
    5772 assert(fractional);
    5773 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
    5774
    5775 /* if no cover was found we stop the separation routine */
    5776 if( coverfound )
    5777 {
    5778 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
    5779 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
    5780 * up- and down-lifting for this feasible set and all subsequent feasible sets.
    5781 */
    5782 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
    5783 &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
    5784 }
    5785 }
    5786
    5787 TERMINATE:
    5788 /* frees temporary memory */
    5789 SCIPfreeBufferArray(scip, &noncovervars);
    5790 SCIPfreeBufferArray(scip, &covervars);
    5791 SCIPfreeBufferArray(scip, &solvals);
    5792
    5793 return SCIP_OKAY;
    5794}
    5795
    5796/* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
    5798 SCIP* scip, /**< SCIP data structure */
    5799 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
    5800 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
    5801 int nknapvars, /**< number of variables in the continuous knapsack constraint */
    5802 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
    5803 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
    5804 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
    5805 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
    5806 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
    5807 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
    5808 int* ncuts /**< pointer to add up the number of found cuts */
    5809 )
    5810{
    5811 SCIP_VAR** binvars;
    5812 SCIP_VAR** consvars;
    5813 SCIP_Real* binvals;
    5814 SCIP_Longint* consvals;
    5815 SCIP_Longint minact;
    5816 SCIP_Longint maxact;
    5817 SCIP_Real intscalar;
    5818 SCIP_Bool success;
    5819 int nbinvars;
    5820 int nconsvars;
    5821 int i;
    5822
    5823 int* tmpindices;
    5824 int tmp;
    5825 SCIP_CONSHDLR* conshdlr;
    5826 SCIP_CONSHDLRDATA* conshdlrdata;
    5827 SCIP_Bool noknapsackconshdlr;
    5828 SCIP_Bool usegubs;
    5829
    5830 assert(nknapvars > 0);
    5831 assert(knapvars != NULL);
    5832 assert(cutoff != NULL);
    5833
    5834 tmpindices = NULL;
    5835
    5836 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
    5837 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
    5838
    5839 binvars = SCIPgetVars(scip);
    5840
    5841 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
    5842 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    5843
    5844 *cutoff = FALSE;
    5845
    5846 if( nbinvars == 0 )
    5847 return SCIP_OKAY;
    5848
    5849 /* set up data structures */
    5850 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
    5851 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
    5852
    5853 /* get conshdlrdata to use cleared memory */
    5854 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    5855 if( conshdlr == NULL )
    5856 {
    5857 noknapsackconshdlr = TRUE;
    5858 usegubs = DEFAULT_USEGUBS;
    5859
    5860 SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
    5861 BMSclearMemoryArray(binvals, nbinvars);
    5862 }
    5863 else
    5864 {
    5865 noknapsackconshdlr = FALSE;
    5866 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5867 assert(conshdlrdata != NULL);
    5868 usegubs = conshdlrdata->usegubs;
    5869
    5870 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
    5871
    5872 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
    5873 * change their types to SCIP_VARTYPE_BINARY during presolving
    5874 */
    5875 if( conshdlrdata->reals1size == 0 )
    5876 {
    5877 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
    5878 conshdlrdata->reals1size = 1;
    5879 conshdlrdata->reals1[0] = 0.0;
    5880 }
    5881
    5882 assert(conshdlrdata->reals1size > 0);
    5883
    5884 /* next if condition should normally not be true, because it means that presolving has created more binary
    5885 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
    5886 * transform all integers into their binary representation then it maybe happens
    5887 */
    5888 if( conshdlrdata->reals1size < nbinvars )
    5889 {
    5890 int oldsize = conshdlrdata->reals1size;
    5891
    5892 conshdlrdata->reals1size = nbinvars;
    5893 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
    5894 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
    5895 }
    5896 binvals = conshdlrdata->reals1;
    5897
    5898 /* check for cleared array, all entries have to be zero */
    5899#ifndef NDEBUG
    5900 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
    5901 {
    5902 assert(binvals[tmp] == 0);
    5903 }
    5904#endif
    5905 }
    5906
    5907 tmp = 0;
    5908
    5909 /* relax continuous knapsack constraint:
    5910 * 1. make all variables binary:
    5911 * if x_j is continuous or integer variable substitute:
    5912 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
    5913 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
    5914 * 2. convert coefficients of all variables to positive integers:
    5915 * - scale all coefficients a_j to a~_j integral
    5916 * - substitute x~_j = 1 - x_j if a~_j < 0
    5917 */
    5918
    5919 /* replace integer and continuous variables with binary variables */
    5920 for( i = 0; i < nknapvars; i++ )
    5921 {
    5922 SCIP_VAR* var;
    5923
    5924 var = knapvars[i];
    5925
    5926 if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
    5927 {
    5928 SCIP_Real solval;
    5929 assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
    5930
    5931 solval = SCIPgetSolVal(scip, sol, var);
    5932
    5933 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
    5934 if( SCIPisFeasLT(scip, solval, 0.0 )
    5935 || SCIPisFeasGT(scip, solval, 1.0) )
    5936 {
    5937 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
    5938 solval, SCIPvarGetName(var));
    5939 goto TERMINATE;
    5940 }
    5941
    5942 binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
    5943 if( !noknapsackconshdlr )
    5944 {
    5945 assert(tmpindices != NULL);
    5946
    5947 tmpindices[tmp] = SCIPvarGetProbindex(var);
    5948 ++tmp;
    5949 }
    5950 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
    5951 }
    5952 else if( valscale * knapvals[i] > 0.0 )
    5953 {
    5954 SCIP_VAR** zvlb;
    5955 SCIP_Real* bvlb;
    5956 SCIP_Real* dvlb;
    5957 SCIP_Real bestlbsol;
    5958 int bestlbtype;
    5959 int nvlb;
    5960 int j;
    5961
    5962 /* a_j > 0: substitution with lb or vlb */
    5963 nvlb = SCIPvarGetNVlbs(var);
    5964 zvlb = SCIPvarGetVlbVars(var);
    5965 bvlb = SCIPvarGetVlbCoefs(var);
    5966 dvlb = SCIPvarGetVlbConstants(var);
    5967
    5968 /* search for lb or vlb with maximal bound value */
    5969 bestlbsol = SCIPvarGetLbGlobal(var);
    5970 bestlbtype = -1;
    5971 for( j = 0; j < nvlb; j++ )
    5972 {
    5973 /* use only numerical stable vlb with binary variable z */
    5974 if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
    5975 {
    5976 SCIP_Real vlbsol;
    5977
    5978 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
    5979 (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
    5980 {
    5981 *cutoff = TRUE;
    5982 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
    5984 bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
    5985 goto TERMINATE;
    5986 }
    5987
    5988 assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
    5989 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
    5990 if( SCIPisGE(scip, vlbsol, bestlbsol) )
    5991 {
    5992 bestlbsol = vlbsol;
    5993 bestlbtype = j;
    5994 }
    5995 }
    5996 }
    5997
    5998 /* if no lb or vlb with binary variable was found, we have to abort */
    5999 if( SCIPisInfinity(scip, -bestlbsol) )
    6000 goto TERMINATE;
    6001
    6002 if( bestlbtype == -1 )
    6003 {
    6004 rhs -= valscale * knapvals[i] * bestlbsol;
    6005 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
    6006 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
    6007 }
    6008 else
    6009 {
    6010 assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
    6011 rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
    6012 binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
    6013
    6014 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
    6015 goto TERMINATE;
    6016
    6017 if( !noknapsackconshdlr )
    6018 {
    6019 assert(tmpindices != NULL);
    6020
    6021 tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
    6022 ++tmp;
    6023 }
    6024 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
    6025 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
    6026 bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
    6027 SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
    6028 }
    6029 }
    6030 else
    6031 {
    6032 SCIP_VAR** zvub;
    6033 SCIP_Real* bvub;
    6034 SCIP_Real* dvub;
    6035 SCIP_Real bestubsol;
    6036 int bestubtype;
    6037 int nvub;
    6038 int j;
    6039
    6040 assert(valscale * knapvals[i] < 0.0);
    6041
    6042 /* a_j < 0: substitution with ub or vub */
    6043 nvub = SCIPvarGetNVubs(var);
    6044 zvub = SCIPvarGetVubVars(var);
    6045 bvub = SCIPvarGetVubCoefs(var);
    6046 dvub = SCIPvarGetVubConstants(var);
    6047
    6048 /* search for ub or vub with minimal bound value */
    6049 bestubsol = SCIPvarGetUbGlobal(var);
    6050 bestubtype = -1;
    6051 for( j = 0; j < nvub; j++ )
    6052 {
    6053 /* use only numerical stable vub with active binary variable z */
    6054 if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
    6055 {
    6056 SCIP_Real vubsol;
    6057
    6058 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
    6059 (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
    6060 {
    6061 *cutoff = TRUE;
    6062 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
    6064 bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
    6065 goto TERMINATE;
    6066 }
    6067
    6068 assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
    6069 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
    6070 if( SCIPisLE(scip, vubsol, bestubsol) )
    6071 {
    6072 bestubsol = vubsol;
    6073 bestubtype = j;
    6074 }
    6075 }
    6076 }
    6077
    6078 /* if no ub or vub with binary variable was found, we have to abort */
    6079 if( SCIPisInfinity(scip, bestubsol) )
    6080 goto TERMINATE;
    6081
    6082 if( bestubtype == -1 )
    6083 {
    6084 rhs -= valscale * knapvals[i] * bestubsol;
    6085 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
    6086 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
    6087 }
    6088 else
    6089 {
    6090 assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
    6091 rhs -= valscale * knapvals[i] * dvub[bestubtype];
    6092 binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
    6093
    6094 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
    6095 goto TERMINATE;
    6096
    6097 if( !noknapsackconshdlr )
    6098 {
    6099 assert(tmpindices != NULL);
    6100
    6101 tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
    6102 ++tmp;
    6103 }
    6104 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
    6105 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
    6106 bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
    6107 SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
    6108 }
    6109 }
    6110 }
    6111
    6112 /* convert coefficients of all (now binary) variables to positive integers:
    6113 * - make all coefficients integral
    6114 * - make all coefficients positive (substitute negated variable)
    6115 */
    6116 nconsvars = 0;
    6117
    6118 /* calculate scalar which makes all coefficients integral in relative allowed difference in between
    6119 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
    6120 */
    6122 KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
    6123 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
    6124
    6125 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
    6126 if( !success )
    6127 intscalar = 1.0;
    6128
    6129 /* make all coefficients integral and positive:
    6130 * - scale a~_j = a_j * intscalar
    6131 * - substitute x~_j = 1 - x_j if a~_j < 0
    6132 */
    6133 rhs = rhs * intscalar;
    6134
    6135 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
    6136 minact = 0;
    6137 maxact = 0;
    6138 for( i = 0; i < nbinvars; i++ )
    6139 {
    6140 SCIP_VAR* var;
    6141 SCIP_Longint val;
    6142
    6143 val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
    6144 if( val == 0 )
    6145 continue;
    6146
    6147 if( val > 0 )
    6148 {
    6149 var = binvars[i];
    6150 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
    6151 val, SCIPvarGetName(var), binvals[i], rhs);
    6152 }
    6153 else
    6154 {
    6155 assert(val < 0);
    6156
    6157 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
    6158 val = -val; /*lint !e2704*/
    6159 rhs += val;
    6160 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
    6161 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
    6162 }
    6163
    6164 if( SCIPvarGetLbLocal(var) > 0.5 )
    6165 minact += val;
    6166 if( SCIPvarGetUbLocal(var) > 0.5 )
    6167 maxact += val;
    6168 consvals[nconsvars] = val;
    6169 consvars[nconsvars] = var;
    6170 nconsvars++;
    6171 }
    6172
    6173 if( nconsvars > 0 )
    6174 {
    6175 SCIP_Longint capacity;
    6176
    6177 assert(consvars != NULL);
    6178 assert(consvals != NULL);
    6179 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
    6180
    6181#ifdef SCIP_DEBUG
    6182 {
    6183 SCIP_Real act;
    6184
    6185 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
    6186 act = 0.0;
    6187 for( i = 0; i < nconsvars; ++i )
    6188 {
    6189 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
    6190 SCIPgetSolVal(scip, sol, consvars[i]));
    6191 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
    6192 }
    6193 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
    6194 capacity, rhs, act, minact, maxact);
    6195 }
    6196#endif
    6197
    6198 if( minact > capacity )
    6199 {
    6200 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
    6201 *cutoff = TRUE;
    6202 goto TERMINATE;
    6203 }
    6204
    6205 if( maxact > capacity )
    6206 {
    6207 /* separate lifted cut from relaxed knapsack constraint */
    6208 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
    6209 }
    6210 }
    6211
    6212 TERMINATE:
    6213 /* free data structures */
    6214 if( noknapsackconshdlr)
    6215 {
    6216 SCIPfreeBufferArray(scip, &binvals);
    6217 }
    6218 else
    6219 {
    6220 /* clear binvals */
    6221 for( --tmp; tmp >= 0; --tmp)
    6222 {
    6223 assert(tmpindices != NULL);
    6224 binvals[tmpindices[tmp]] = 0;
    6225 }
    6226 SCIPfreeBufferArray(scip, &tmpindices);
    6227 }
    6228 SCIPfreeBufferArray(scip, &consvals);
    6229 SCIPfreeBufferArray(scip, &consvars);
    6230
    6231 return SCIP_OKAY;
    6232}
    6233
    6234/** separates given knapsack constraint */
    6235static
    6237 SCIP* scip, /**< SCIP data structure */
    6238 SCIP_CONS* cons, /**< knapsack constraint */
    6239 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
    6240 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
    6241 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
    6242 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    6243 int* ncuts /**< pointer to add up the number of found cuts */
    6244 )
    6245{
    6246 SCIP_CONSDATA* consdata;
    6247 SCIP_Bool violated;
    6248
    6249 assert(ncuts != NULL);
    6250 assert(cutoff != NULL);
    6251 *cutoff = FALSE;
    6252
    6253 consdata = SCIPconsGetData(cons);
    6254 assert(consdata != NULL);
    6255
    6256 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
    6257
    6258 /* check knapsack constraint itself for feasibility */
    6259 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
    6260
    6261 if( violated )
    6262 {
    6263 /* add knapsack constraint as LP row to the LP */
    6264 SCIP_CALL( addRelaxation(scip, cons, cutoff) );
    6265 (*ncuts)++;
    6266 }
    6267 else if( sepacuts )
    6268 {
    6269 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
    6270 consdata->capacity, sol, usegubs, cutoff, ncuts) );
    6271 }
    6272
    6273 return SCIP_OKAY;
    6274}
    6275
    6276/** adds coefficient to constraint data */
    6277static
    6279 SCIP* scip, /**< SCIP data structure */
    6280 SCIP_CONS* cons, /**< knapsack constraint */
    6281 SCIP_VAR* var, /**< variable to add to knapsack */
    6282 SCIP_Longint weight /**< weight of variable in knapsack */
    6283 )
    6284{
    6285 SCIP_CONSDATA* consdata;
    6286
    6287 consdata = SCIPconsGetData(cons);
    6288 assert(consdata != NULL);
    6289 assert(SCIPvarIsBinary(var));
    6290 assert(weight > 0);
    6291
    6292 /* add the new coefficient to the LP row */
    6293 if( consdata->row != NULL )
    6294 {
    6295 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
    6296 }
    6297
    6298 /* check for fixed variable */
    6299 if( SCIPvarGetLbGlobal(var) > 0.5 )
    6300 {
    6301 /* variable is fixed to one: reduce capacity */
    6302 consdata->capacity -= weight;
    6303 }
    6304 else if( SCIPvarGetUbGlobal(var) > 0.5 )
    6305 {
    6306 SCIP_Bool negated;
    6307
    6308 /* get binary representative of variable */
    6309 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
    6310
    6311 /* insert coefficient */
    6312 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
    6313 consdata->vars[consdata->nvars] = var;
    6314 consdata->weights[consdata->nvars] = weight;
    6315 consdata->nvars++;
    6316
    6317 /* capture variable */
    6318 SCIP_CALL( SCIPcaptureVar(scip, var) );
    6319
    6320 /* install the rounding locks of variable */
    6321 SCIP_CALL( lockRounding(scip, cons, var) );
    6322
    6323 /* catch events */
    6324 if( SCIPconsIsTransformed(cons) )
    6325 {
    6326 SCIP_CONSHDLRDATA* conshdlrdata;
    6327
    6328 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    6329 assert(conshdlrdata != NULL);
    6330 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
    6332 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
    6333 &consdata->eventdata[consdata->nvars-1]->filterpos) );
    6334
    6335 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
    6336 consdata->existmultaggr = TRUE;
    6337
    6338 /* mark constraint to be propagated and presolved */
    6340 consdata->presolvedtiming = 0;
    6341 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
    6342 }
    6343
    6344 /* update weight sums */
    6345 updateWeightSums(consdata, var, weight);
    6346
    6347 consdata->sorted = FALSE;
    6348 consdata->cliquepartitioned = FALSE;
    6349 consdata->negcliquepartitioned = FALSE;
    6350 consdata->merged = FALSE;
    6351 }
    6352
    6353 return SCIP_OKAY;
    6354}
    6355
    6356/** deletes coefficient at given position from constraint data */
    6357static
    6359 SCIP* scip, /**< SCIP data structure */
    6360 SCIP_CONS* cons, /**< knapsack constraint */
    6361 int pos /**< position of coefficient to delete */
    6362 )
    6363{
    6364 SCIP_CONSDATA* consdata;
    6365 SCIP_VAR* var;
    6366
    6367 consdata = SCIPconsGetData(cons);
    6368 assert(consdata != NULL);
    6369 assert(0 <= pos && pos < consdata->nvars);
    6370
    6371 var = consdata->vars[pos];
    6372 assert(var != NULL);
    6373 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
    6374
    6375 /* delete the coefficient from the LP row */
    6376 if( consdata->row != NULL )
    6377 {
    6378 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
    6379 }
    6380
    6381 /* remove the rounding locks of variable */
    6382 SCIP_CALL( unlockRounding(scip, cons, var) );
    6383
    6384 /* drop events and mark constraint to be propagated and presolved */
    6385 if( SCIPconsIsTransformed(cons) )
    6386 {
    6387 SCIP_CONSHDLRDATA* conshdlrdata;
    6388
    6389 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    6390 assert(conshdlrdata != NULL);
    6392 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
    6393 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
    6394
    6396 consdata->presolvedtiming = 0;
    6397 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
    6398 }
    6399
    6400 /* decrease weight sums */
    6401 updateWeightSums(consdata, var, -consdata->weights[pos]);
    6402
    6403 /* move the last variable to the free slot */
    6404 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
    6405 consdata->weights[pos] = consdata->weights[consdata->nvars-1];
    6406 if( consdata->eventdata != NULL )
    6407 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
    6408
    6409 /* release variable */
    6410 SCIP_CALL( SCIPreleaseVar(scip, &var) );
    6411
    6412 /* try to use old clique partitions */
    6413 if( consdata->cliquepartitioned )
    6414 {
    6415 assert(consdata->cliquepartition != NULL);
    6416 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
    6417 * change the clique number */
    6418 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
    6419 {
    6420 int oldcliqenum;
    6421
    6422 oldcliqenum = consdata->cliquepartition[pos];
    6423 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
    6424
    6425 /* the following if and else cases assure that we have increasing clique numbers */
    6426 if( consdata->cliquepartition[pos] > pos )
    6427 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
    6428 else
    6429 {
    6430 int i;
    6431 int cliquenumbefore;
    6432
    6433 /* if the old clique number was greater than the new one we have to check that before a bigger clique number
    6434 * occurs the same as the old one is still in the cliquepartition */
    6435 if( oldcliqenum > consdata->cliquepartition[pos] )
    6436 {
    6437 for( i = 0; i < consdata->nvars; ++i )
    6438 if( oldcliqenum == consdata->cliquepartition[i] )
    6439 break;
    6440 else if( oldcliqenum < consdata->cliquepartition[i] )
    6441 {
    6442 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
    6443 break;
    6444 }
    6445 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
    6446 * the biggest index, so decrease the number of cliques
    6447 */
    6448 if( i == consdata->nvars )
    6449 --(consdata->ncliques);
    6450 }
    6451 /* if the old clique number was smaller than the new one we have to check the front for an element with
    6452 * clique number minus 1 */
    6453 else if( oldcliqenum < consdata->cliquepartition[pos] )
    6454 {
    6455 cliquenumbefore = consdata->cliquepartition[pos] - 1;
    6456 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
    6457
    6458 if( i < cliquenumbefore )
    6459 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
    6460 }
    6461 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
    6462 else if( pos == consdata->nvars - 1)
    6463 {
    6464 cliquenumbefore = consdata->cliquepartition[pos];
    6465 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
    6466
    6467 if( i < cliquenumbefore )
    6468 --(consdata->ncliques);
    6469 }
    6470 /* if the old clique number is equal to the new one the cliquepartition should be ok */
    6471 }
    6472 }
    6473 else
    6474 --(consdata->ncliques);
    6475 }
    6476
    6477 if( consdata->negcliquepartitioned )
    6478 {
    6479 assert(consdata->negcliquepartition != NULL);
    6480 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
    6481 * change the clique number */
    6482 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
    6483 {
    6484 int oldcliqenum;
    6485
    6486 oldcliqenum = consdata->negcliquepartition[pos];
    6487 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
    6488
    6489 /* the following if and else cases assure that we have increasing clique numbers */
    6490 if( consdata->negcliquepartition[pos] > pos )
    6491 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
    6492 else
    6493 {
    6494 int i;
    6495 int cliquenumbefore;
    6496
    6497 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
    6498 * occurs, the same as the old one occurs */
    6499 if( oldcliqenum > consdata->negcliquepartition[pos] )
    6500 {
    6501 for( i = 0; i < consdata->nvars; ++i )
    6502 if( oldcliqenum == consdata->negcliquepartition[i] )
    6503 break;
    6504 else if( oldcliqenum < consdata->negcliquepartition[i] )
    6505 {
    6506 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
    6507 break;
    6508 }
    6509 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
    6510 * the biggest index, so decrease the number of negated cliques
    6511 */
    6512 if( i == consdata->nvars )
    6513 --(consdata->nnegcliques);
    6514 }
    6515 /* if the old clique number was smaller than the new one we have to check the front for an element with
    6516 * clique number minus 1 */
    6517 else if( oldcliqenum < consdata->negcliquepartition[pos] )
    6518 {
    6519 cliquenumbefore = consdata->negcliquepartition[pos] - 1;
    6520 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
    6521
    6522 if( i < cliquenumbefore )
    6523 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
    6524 }
    6525 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
    6526 else if( pos == consdata->nvars - 1)
    6527 {
    6528 cliquenumbefore = consdata->negcliquepartition[pos];
    6529 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
    6530
    6531 if( i < cliquenumbefore )
    6532 --(consdata->nnegcliques);
    6533 }
    6534 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
    6535 }
    6536 }
    6537 else
    6538 --(consdata->nnegcliques);
    6539 }
    6540
    6541 --(consdata->nvars);
    6542
    6543 return SCIP_OKAY;
    6544}
    6545
    6546/** removes all items with weight zero from knapsack constraint */
    6547static
    6549 SCIP* scip, /**< SCIP data structure */
    6550 SCIP_CONS* cons /**< knapsack constraint */
    6551 )
    6552{
    6553 SCIP_CONSDATA* consdata;
    6554 int v;
    6555
    6556 consdata = SCIPconsGetData(cons);
    6557 assert(consdata != NULL);
    6558
    6559 for( v = consdata->nvars-1; v >= 0; --v )
    6560 {
    6561 if( consdata->weights[v] == 0 )
    6562 {
    6563 SCIP_CALL( delCoefPos(scip, cons, v) );
    6564 }
    6565 }
    6566
    6567 return SCIP_OKAY;
    6568}
    6569
    6570/* perform deletion of variables in all constraints of the constraint handler */
    6571static
    6573 SCIP* scip, /**< SCIP data structure */
    6574 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6575 SCIP_CONS** conss, /**< array of constraints */
    6576 int nconss /**< number of constraints */
    6577 )
    6578{
    6579 SCIP_CONSDATA* consdata;
    6580 int i;
    6581 int v;
    6582
    6583 assert(scip != NULL);
    6584 assert(conshdlr != NULL);
    6585 assert(conss != NULL);
    6586 assert(nconss >= 0);
    6587
    6589
    6590 /* iterate over all constraints */
    6591 for( i = 0; i < nconss; i++ )
    6592 {
    6593 consdata = SCIPconsGetData(conss[i]);
    6594
    6595 /* constraint is marked, that some of its variables were deleted */
    6596 if( consdata->varsdeleted )
    6597 {
    6598 /* iterate over all variables of the constraint and delete them from the constraint */
    6599 for( v = consdata->nvars - 1; v >= 0; --v )
    6600 {
    6601 if( SCIPvarIsDeleted(consdata->vars[v]) )
    6602 {
    6603 SCIP_CALL( delCoefPos(scip, conss[i], v) );
    6604 }
    6605 }
    6606 consdata->varsdeleted = FALSE;
    6607 }
    6608 }
    6609
    6610 return SCIP_OKAY;
    6611}
    6612
    6613/** replaces multiple occurrences of a variable or its negation by a single coefficient */
    6614static
    6616 SCIP* scip, /**< SCIP data structure */
    6617 SCIP_CONS* cons, /**< knapsack constraint */
    6618 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
    6619 )
    6620{
    6621 SCIP_CONSDATA* consdata;
    6622 int v;
    6623 int prev;
    6624
    6625 assert(scip != NULL);
    6626 assert(cons != NULL);
    6627 assert(cutoff != NULL);
    6628
    6629 consdata = SCIPconsGetData(cons);
    6630 assert(consdata != NULL);
    6631
    6632 *cutoff = FALSE;
    6633
    6634 if( consdata->merged )
    6635 return SCIP_OKAY;
    6636
    6637 if( consdata->nvars <= 1 )
    6638 {
    6639 consdata->merged = TRUE;
    6640 return SCIP_OKAY;
    6641 }
    6642
    6643 assert(consdata->vars != NULL || consdata->nvars == 0);
    6644
    6645 /* sorting array after indices of variables, that's only for faster merging */
    6646 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
    6647 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
    6648
    6649 /* knapsack-sorting (decreasing weights) now lost */
    6650 consdata->sorted = FALSE;
    6651
    6652 v = consdata->nvars - 1;
    6653 prev = v - 1;
    6654 /* loop backwards through the items: deletion only affects rear items */
    6655 while( prev >= 0 )
    6656 {
    6657 SCIP_VAR* var1;
    6658 SCIP_VAR* var2;
    6659 SCIP_Bool negated1;
    6660 SCIP_Bool negated2;
    6661
    6662 negated1 = FALSE;
    6663 negated2 = FALSE;
    6664
    6665 var1 = consdata->vars[v];
    6666 assert(SCIPvarIsBinary(var1));
    6669 {
    6670 var1 = SCIPvarGetNegatedVar(var1);
    6671 negated1 = TRUE;
    6672 }
    6673 assert(var1 != NULL);
    6674
    6675 var2 = consdata->vars[prev];
    6676 assert(SCIPvarIsBinary(var2));
    6679 {
    6680 var2 = SCIPvarGetNegatedVar(var2);
    6681 negated2 = TRUE;
    6682 }
    6683 assert(var2 != NULL);
    6684
    6685 if( var1 == var2 )
    6686 {
    6687 /* both variables are either active or negated */
    6688 if( negated1 == negated2 )
    6689 {
    6690 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
    6691 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
    6692 SCIP_CALL( delCoefPos(scip, cons, v) );
    6693 }
    6694 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
    6695 * and delete item of smaller weight
    6696 */
    6697 else if( consdata->weights[v] == consdata->weights[prev] )
    6698 {
    6699 /* both variables eliminate themselves: w*x + w*(1-x) == w */
    6700 consdata->capacity -= consdata->weights[v];
    6701 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
    6702 SCIP_CALL( delCoefPos(scip, cons, prev) );
    6703
    6704 --prev;
    6705 }
    6706 else if( consdata->weights[v] < consdata->weights[prev] )
    6707 {
    6708 consdata->capacity -= consdata->weights[v];
    6709 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
    6710 assert(consdata->weights[prev] > 0);
    6711 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
    6712 }
    6713 else
    6714 {
    6715 consdata->capacity -= consdata->weights[prev];
    6716 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
    6717 assert(consdata->weights[v] > 0);
    6718 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
    6719 /* restore order iff necessary */
    6720 if( consdata->nvars != v ) /* otherwise the order still stands */
    6721 {
    6722 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
    6723 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
    6724 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
    6725 --prev;
    6726 else /* we need to let v at the same position*/
    6727 {
    6728 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
    6729 /* don't decrease v, the same variable may exist up front */
    6730 --prev;
    6731 continue;
    6732 }
    6733 }
    6734 }
    6735 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
    6736 }
    6737 v = prev;
    6738 --prev;
    6739 }
    6740
    6741 consdata->merged = TRUE;
    6742
    6743 /* check infeasibility */
    6744 if( consdata->onesweightsum > consdata->capacity )
    6745 {
    6746 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
    6747 *cutoff = TRUE;
    6748 return SCIP_OKAY;
    6749 }
    6750
    6751 return SCIP_OKAY;
    6752}
    6753
    6754/** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
    6755 * fixings (dual reductions)
    6756 */
    6757static
    6759 SCIP* scip, /**< SCIP data structure */
    6760 SCIP_CONS* cons, /**< knapsack constraint */
    6761 int* nfixedvars, /**< pointer to count number of fixings */
    6762 int* ndelconss, /**< pointer to count number of deleted constraints */
    6763 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
    6764 )
    6765{
    6766 SCIP_CONSDATA* consdata;
    6767 SCIP_VAR** vars;
    6768 SCIP_Real* profits;
    6769 int* solitems;
    6770 int* nonsolitems;
    6771 int* items;
    6772 SCIP_Real solval;
    6773 SCIP_Bool infeasible;
    6774 SCIP_Bool tightened;
    6775 SCIP_Bool applicable;
    6776 int nsolitems;
    6777 int nnonsolitems;
    6778 int nvars;
    6779 int v;
    6780
    6781 assert(!SCIPconsIsModifiable(cons));
    6782
    6783 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
    6784 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
    6785 * added to the problems have the check flag set to FALSE
    6786 */
    6787 if( !SCIPconsIsChecked(cons) )
    6788 return SCIP_OKAY;
    6789
    6790 consdata = SCIPconsGetData(cons);
    6791 assert(consdata != NULL);
    6792
    6793 nvars = consdata->nvars;
    6794 vars = consdata->vars;
    6795
    6798 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
    6799 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
    6800
    6801 applicable = TRUE;
    6802
    6803 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
    6804 * collect object values which are the profits of the knapsack problem
    6805 */
    6806 for( v = 0; v < nvars; ++v )
    6807 {
    6808 SCIP_VAR* var;
    6809 SCIP_Bool negated;
    6810
    6811 var = vars[v];
    6812 assert(var != NULL);
    6813
    6814 /* the variable should not be (globally) fixed */
    6815 assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
    6816
    6819 {
    6820 applicable = FALSE;
    6821 break;
    6822 }
    6823
    6824 negated = FALSE;
    6825
    6826 /* get the active variable */
    6827 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
    6828 assert(SCIPvarIsActive(var));
    6829
    6830 if( negated )
    6831 profits[v] = SCIPvarGetObj(var);
    6832 else
    6833 profits[v] = -SCIPvarGetObj(var);
    6834
    6835 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
    6836 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
    6837 items[v] = v;
    6838 }
    6839
    6840 if( applicable )
    6841 {
    6842 SCIP_Bool success;
    6843
    6844 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
    6846
    6847 /* solve knapsack problem exactly */
    6848 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
    6849 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
    6850
    6851 if( success )
    6852 {
    6853 SCIP_VAR* var;
    6854
    6855 /* apply solution of the knapsack as dual reductions */
    6856 for( v = 0; v < nsolitems; ++v )
    6857 {
    6858 var = vars[solitems[v]];
    6859 assert(var != NULL);
    6860
    6861 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
    6863 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
    6864 assert(!infeasible);
    6865 assert(tightened);
    6866 (*nfixedvars)++;
    6867 }
    6868
    6869 for( v = 0; v < nnonsolitems; ++v )
    6870 {
    6871 var = vars[nonsolitems[v]];
    6872 assert(var != NULL);
    6873
    6874 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
    6876 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
    6877 assert(!infeasible);
    6878 assert(tightened);
    6879 (*nfixedvars)++;
    6880 }
    6881
    6882 SCIP_CALL( SCIPdelCons(scip, cons) );
    6883 (*ndelconss)++;
    6884 (*deleted) = TRUE;
    6885 }
    6886 }
    6887
    6888 SCIPfreeBufferArray(scip, &nonsolitems);
    6889 SCIPfreeBufferArray(scip, &solitems);
    6890 SCIPfreeBufferArray(scip, &items);
    6891 SCIPfreeBufferArray(scip, &profits);
    6892
    6893 return SCIP_OKAY;
    6894}
    6895
    6896/** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
    6897 * constraint enters the LP by setting the initial and separated flag to FALSE
    6898 */
    6899static
    6901 SCIP* scip, /**< SCIP data structure */
    6902 SCIP_CONS* cons, /**< knapsack constraint */
    6903 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
    6904 )
    6905{
    6906 SCIP_CONSDATA* consdata;
    6907 SCIP_VAR** vars;
    6908 SCIP_VAR* var;
    6909 SCIP_Real offset;
    6910 SCIP_Real scale;
    6911 SCIP_Real objval;
    6912 SCIP_Bool applicable;
    6913 SCIP_Bool negated;
    6914 int nobjvars;
    6915 int nvars;
    6916 int v;
    6917
    6918 assert(scip != NULL);
    6919 assert(cons != NULL);
    6920 assert(conshdlrdata != NULL);
    6921
    6922 consdata = SCIPconsGetData(cons);
    6923 assert(consdata != NULL);
    6924
    6925 nvars = consdata->nvars;
    6926 nobjvars = SCIPgetNObjVars(scip);
    6927
    6928 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
    6929 * and/or separated flag is set to FALSE
    6930 */
    6931 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
    6932 return SCIP_OKAY;
    6933
    6934 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
    6935 * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
    6936 */
    6937 if( nobjvars == 0 )
    6938 return SCIP_OKAY;
    6939
    6940 vars = consdata->vars;
    6941 assert(vars != NULL);
    6942
    6943 applicable = TRUE;
    6944 offset = 0.0;
    6945 scale = 1.0;
    6946
    6947 for( v = 0; v < nvars && applicable; ++v )
    6948 {
    6949 negated = FALSE;
    6950 var = vars[v];
    6951 assert(var != NULL);
    6952
    6953 if( SCIPvarIsNegated(var) )
    6954 {
    6955 negated = TRUE;
    6956 var = SCIPvarGetNegatedVar(var);
    6957 assert(var != NULL);
    6958 }
    6959
    6960 objval = SCIPvarGetObj(var);
    6961
    6962 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
    6963 if( SCIPisZero(scip, objval) )
    6964 applicable = FALSE;
    6965 else
    6966 {
    6967 SCIP_Real weight;
    6968
    6969 weight = (SCIP_Real)consdata->weights[v];
    6970
    6971 if( negated )
    6972 {
    6973 if( v == 0 )
    6974 {
    6975 /* the first variable defines the scale */
    6976 scale = weight / -objval;
    6977
    6978 offset += weight;
    6979 }
    6980 else if( SCIPisEQ(scip, -objval * scale, weight) )
    6981 offset += weight;
    6982 else
    6983 applicable = FALSE;
    6984 }
    6985 else if( v == 0 )
    6986 {
    6987 /* the first variable define the scale */
    6988 scale = weight / objval;
    6989 }
    6990 else if( !SCIPisEQ(scip, objval * scale, weight) )
    6991 applicable = FALSE;
    6992 }
    6993 }
    6994
    6995 if( applicable )
    6996 {
    6997 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
    6998 {
    6999 SCIP_Real cutoffbound;
    7000
    7001 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
    7004
    7005 cutoffbound = (consdata->capacity - offset) / scale;
    7006
    7007 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
    7008 SCIPconsGetName(cons), cutoffbound);
    7009
    7010 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
    7011 * still excepted
    7012 */
    7013 cutoffbound += SCIPcutoffbounddelta(scip);
    7014
    7015 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
    7016 SCIPconsGetName(cons), cutoffbound);
    7017
    7018 if( cutoffbound < SCIPgetCutoffbound(scip) )
    7019 {
    7020 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
    7021
    7022 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
    7023 }
    7024 else
    7025 {
    7026 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
    7027 * propagation
    7028 */
    7031 }
    7032 }
    7033 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
    7034 {
    7035 SCIP_Real lowerbound;
    7036
    7037 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
    7040
    7041 lowerbound = (consdata->capacity - offset) / scale;
    7042
    7043 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
    7044 SCIPconsGetName(cons), lowerbound);
    7045
    7047 }
    7048 }
    7049
    7050 return SCIP_OKAY;
    7051}
    7052
    7053/** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
    7054 * weight of one variable is greater or equal another weight and both variables are in the same cliques */
    7055static
    7057 SCIP* scip, /**< SCIP data structure */
    7058 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
    7059 SCIP_VAR** vars, /**< array for sorted variables */
    7060 SCIP_Longint* weights, /**< array for sorted weights */
    7061 int* cliquestartposs, /**< starting position array for each clique */
    7062 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
    7063 )
    7064{
    7065 SCIP_VAR** origvars;
    7066 int norigvars;
    7067 SCIP_Longint* origweights;
    7068 int* cliquepartition;
    7069 int ncliques;
    7070
    7071 SCIP_VAR*** varpointers;
    7072 SCIP_Longint** weightpointers;
    7073 int* cliquecount;
    7074
    7075 int nextpos;
    7076 int c;
    7077 int v;
    7078
    7079 assert(scip != NULL);
    7080 assert(consdata != NULL);
    7081 assert(vars != NULL);
    7082 assert(weights != NULL);
    7083 assert(cliquestartposs != NULL);
    7084
    7085 origweights = consdata->weights;
    7086 origvars = consdata->vars;
    7087 norigvars = consdata->nvars;
    7088
    7089 assert(origvars != NULL || norigvars == 0);
    7090 assert(origweights != NULL || norigvars == 0);
    7091
    7092 if( norigvars == 0 )
    7093 return SCIP_OKAY;
    7094
    7095 if( usenegatedclique )
    7096 {
    7097 assert(consdata->negcliquepartitioned);
    7098
    7099 cliquepartition = consdata->negcliquepartition;
    7100 ncliques = consdata->nnegcliques;
    7101 }
    7102 else
    7103 {
    7104 assert(consdata->cliquepartitioned);
    7105
    7106 cliquepartition = consdata->cliquepartition;
    7107 ncliques = consdata->ncliques;
    7108 }
    7109
    7110 assert(cliquepartition != NULL);
    7111 assert(ncliques > 0);
    7112
    7113 /* we first count all clique items and alloc temporary memory for a bucket sort */
    7114 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
    7115 BMSclearMemoryArray(cliquecount, ncliques);
    7116
    7117 /* first we count for each clique the number of elements */
    7118 for( v = norigvars - 1; v >= 0; --v )
    7119 {
    7120 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
    7121 ++(cliquecount[cliquepartition[v]]);
    7122 }
    7123
    7124 /*@todo: maybe it is better to put largest cliques up front */
    7125
    7126#ifndef NDEBUG
    7127 BMSclearMemoryArray(vars, norigvars);
    7128 BMSclearMemoryArray(weights, norigvars);
    7129#endif
    7130 SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
    7131 SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
    7132
    7133 nextpos = 0;
    7134 /* now we initialize all start pointers for each clique, so they will be ordered */
    7135 for( c = 0; c < ncliques; ++c )
    7136 {
    7137 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
    7138 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
    7139 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
    7140 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
    7141 * vars[7]
    7142 *
    7143 */
    7144 varpointers[c] = (SCIP_VAR**) (vars + nextpos);
    7145 cliquestartposs[c] = nextpos;
    7146 weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
    7147 assert(cliquecount[c] > 0);
    7148 nextpos += cliquecount[c];
    7149 assert(nextpos > 0);
    7150 }
    7151 assert(nextpos == norigvars);
    7152 cliquestartposs[c] = nextpos;
    7153
    7154 /* now we copy all variable and weights to the right order */
    7155 for( v = 0; v < norigvars; ++v )
    7156 {
    7157 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
    7158 ++(varpointers[cliquepartition[v]]);
    7159 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
    7160 ++(weightpointers[cliquepartition[v]]);
    7161 }
    7162#ifndef NDEBUG
    7163 for( v = 0; v < norigvars; ++v )
    7164 {
    7165 assert(vars[v] != NULL);
    7166 assert(weights[v] > 0);
    7167 }
    7168#endif
    7169
    7170 /* free temporary memory */
    7171 SCIPfreeBufferArray(scip, &weightpointers);
    7172 SCIPfreeBufferArray(scip, &varpointers);
    7173 SCIPfreeBufferArray(scip, &cliquecount);
    7174
    7175 return SCIP_OKAY;
    7176}
    7177
    7178/** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
    7179static
    7181 SCIP* scip, /**< SCIP data structure */
    7182 SCIP_CONS* cons, /**< knapsack constraint */
    7183 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
    7184 * information is not needed; in this case, we apply all fixings
    7185 * instead of stopping after the first infeasible one */
    7186 )
    7187{
    7188 SCIP_CONSDATA* consdata;
    7189 int v;
    7190
    7191 assert(scip != NULL);
    7192 assert(cons != NULL);
    7193
    7194 consdata = SCIPconsGetData(cons);
    7195 assert(consdata != NULL);
    7196 assert(consdata->nvars == 0 || consdata->vars != NULL);
    7197
    7198 if( cutoff != NULL )
    7199 *cutoff = FALSE;
    7200
    7201 SCIPdebugMsg(scip, "apply fixings:\n");
    7203
    7204 /* check infeasibility */
    7205 if ( consdata->onesweightsum > consdata->capacity )
    7206 {
    7207 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
    7208
    7209 if( cutoff != NULL )
    7210 *cutoff = TRUE;
    7211
    7212 return SCIP_OKAY;
    7213 }
    7214
    7215 /* all multi-aggregations should be resolved */
    7216 consdata->existmultaggr = FALSE;
    7217
    7218 v = 0;
    7219 while( v < consdata->nvars )
    7220 {
    7221 SCIP_VAR* var;
    7222
    7223 var = consdata->vars[v];
    7224 assert(SCIPvarIsBinary(var));
    7225
    7226 if( SCIPvarGetLbGlobal(var) > 0.5 )
    7227 {
    7228 assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
    7229 consdata->capacity -= consdata->weights[v];
    7230 SCIP_CALL( delCoefPos(scip, cons, v) );
    7231 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
    7232 }
    7233 else if( SCIPvarGetUbGlobal(var) < 0.5 )
    7234 {
    7235 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
    7236 SCIP_CALL( delCoefPos(scip, cons, v) );
    7237 }
    7238 else
    7239 {
    7240 SCIP_VAR* repvar;
    7241 SCIP_VAR* negvar;
    7242 SCIP_VAR* workvar;
    7243 SCIP_Longint weight;
    7244 SCIP_Bool negated;
    7245
    7246 weight = consdata->weights[v];
    7247
    7248 /* get binary representative of variable */
    7249 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
    7250 assert(repvar != NULL);
    7251
    7252 /* check for multi-aggregation */
    7253 if( SCIPvarIsNegated(repvar) )
    7254 {
    7255 workvar = SCIPvarGetNegatedVar(repvar);
    7256 assert(workvar != NULL);
    7257 negated = TRUE;
    7258 }
    7259 else
    7260 {
    7261 workvar = repvar;
    7262 negated = FALSE;
    7263 }
    7264
    7265 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
    7266 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
    7267 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
    7268 *
    7269 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
    7270 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
    7271 *
    7272 * The explanation for the following block:
    7273 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
    7274 * weight * (a_1*y_1 + ... + a_n*y_n + c).
    7275 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
    7276 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
    7277 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
    7278 * 2) For all replacement variable we check:
    7279 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
    7280 * capacity -= weight * a_i caused by the negation of y_i.
    7281 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
    7282 * 3a) If repvar was not negated we need to subtract weight * c from capacity.
    7283 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
    7284 * weight in this case.
    7285 */
    7287 {
    7288 SCIP_VAR** aggrvars;
    7289 SCIP_Real* aggrscalars;
    7290 SCIP_Real aggrconst;
    7291 int naggrvars;
    7292 int i;
    7293
    7295 naggrvars = SCIPvarGetMultaggrNVars(workvar);
    7296 aggrvars = SCIPvarGetMultaggrVars(workvar);
    7297 aggrscalars = SCIPvarGetMultaggrScalars(workvar);
    7298 aggrconst = SCIPvarGetMultaggrConstant(workvar);
    7299 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
    7300
    7301 if( !SCIPisIntegral(scip, weight * aggrconst) )
    7302 {
    7303 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
    7304 return SCIP_ERROR;
    7305 }
    7306
    7307 /* if workvar was negated, we have to flip the weight */
    7308 if( negated )
    7309 weight *= -1;
    7310
    7311 for( i = naggrvars - 1; i >= 0; --i )
    7312 {
    7313 assert(aggrvars != NULL);
    7314 assert(aggrscalars != NULL);
    7315
    7316 if( !SCIPvarIsBinary(aggrvars[i]) )
    7317 {
    7318 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
    7319 SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
    7320 return SCIP_ERROR;
    7321 }
    7322 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
    7323 {
    7324 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
    7325 return SCIP_ERROR;
    7326 }
    7327 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
    7328 if( SCIPisNegative(scip, weight * aggrscalars[i]) )
    7329 {
    7330 SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar) );
    7331 assert(negvar != NULL);
    7332 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
    7333 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
    7334 }
    7335 else
    7336 {
    7337 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
    7338 }
    7339 }
    7340 /* delete old coefficient */
    7341 SCIP_CALL( delCoefPos(scip, cons, v) );
    7342
    7343 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
    7344 if( negated )
    7345 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
    7346 else
    7347 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
    7348
    7349 if( consdata->capacity < 0 )
    7350 {
    7351 if( cutoff != NULL )
    7352 {
    7353 *cutoff = TRUE;
    7354 break;
    7355 }
    7356 }
    7357 }
    7358 /* check, if the variable should be replaced with the representative */
    7359 else if( repvar != var )
    7360 {
    7361 /* delete old (aggregated) variable */
    7362 SCIP_CALL( delCoefPos(scip, cons, v) );
    7363
    7364 /* add representative instead */
    7365 SCIP_CALL( addCoef(scip, cons, repvar, weight) );
    7366 }
    7367 else
    7368 ++v;
    7369 }
    7370 }
    7371 assert(consdata->onesweightsum == 0);
    7372
    7373 SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
    7375
    7376 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
    7377 * clean up the constraint
    7378 */
    7379 if( cutoff != NULL && !(*cutoff) )
    7380 {
    7381 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    7382 SCIPdebugMsg(scip, "after applyFixings and merging:\n");
    7384 }
    7385
    7386 return SCIP_OKAY;
    7387}
    7388
    7389
    7390/** propagation method for knapsack constraints */
    7391static
    7393 SCIP* scip, /**< SCIP data structure */
    7394 SCIP_CONS* cons, /**< knapsack constraint */
    7395 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
    7396 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
    7397 int* nfixedvars, /**< pointer to count number of fixings */
    7398 SCIP_Bool usenegatedclique /**< should negated clique information be used */
    7399 )
    7400{
    7401 SCIP_CONSDATA* consdata;
    7402 SCIP_Bool infeasible;
    7403 SCIP_Bool tightened;
    7404 SCIP_Longint* secondmaxweights;
    7405 SCIP_Longint minweightsum;
    7406 SCIP_Longint residualcapacity;
    7407
    7408 int nvars;
    7409 int i;
    7410 int nnegcliques;
    7411
    7412 SCIP_VAR** myvars;
    7413 SCIP_Longint* myweights;
    7414 int* cliquestartposs;
    7415 int* cliqueendposs;
    7416 SCIP_Longint localminweightsum;
    7417 SCIP_Bool foundmax;
    7418 int c;
    7419
    7420 assert(scip != NULL);
    7421 assert(cons != NULL);
    7422 assert(cutoff != NULL);
    7423 assert(redundant != NULL);
    7424 assert(nfixedvars != NULL);
    7425
    7426 consdata = SCIPconsGetData(cons);
    7427 assert(consdata != NULL);
    7428
    7429 *cutoff = FALSE;
    7430 *redundant = FALSE;
    7431
    7432 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
    7433
    7434 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
    7436 {
    7437 SCIP_CALL( SCIPincConsAge(scip, cons) );
    7438 }
    7439
    7440#ifndef NDEBUG
    7441 /* assert that only active or negated variables are present */
    7442 for( i = 0; i < consdata->nvars && consdata->merged; ++i )
    7443 {
    7444 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
    7445 }
    7446#endif
    7447
    7448 usenegatedclique = usenegatedclique && consdata->merged;
    7449
    7450 /* init for debugging */
    7451 myvars = NULL;
    7452 myweights = NULL;
    7453 cliquestartposs = NULL;
    7454 secondmaxweights = NULL;
    7455 minweightsum = 0;
    7456 nvars = consdata->nvars;
    7457 /* make sure, the items are sorted by non-increasing weight */
    7458 sortItems(consdata);
    7459
    7460 do
    7461 {
    7462 localminweightsum = 0;
    7463
    7464 /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
    7465 * a negated clique means, that at most one of the clique variables can be zero
    7466 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
    7467 *
    7468 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
    7469 * since replacing i with the element of maximal weight leads to infeasibility
    7470 */
    7471 if( usenegatedclique && nvars > 0 )
    7472 {
    7473 SCIP_CONSHDLRDATA* conshdlrdata;
    7474 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    7475 assert(conshdlrdata != NULL);
    7476
    7477 /* compute clique partitions */
    7478 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
    7479 nnegcliques = consdata->nnegcliques;
    7480
    7481 /* if we have no real negated cliques we can stop here */
    7482 if( nnegcliques == nvars )
    7483 {
    7484 /* run the standard algorithm that does not involve cliques */
    7485 usenegatedclique = FALSE;
    7486 break;
    7487 }
    7488
    7489 /* allocate temporary memory and initialize it */
    7490 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
    7491 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
    7492 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
    7493 SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
    7494 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
    7495 BMSclearMemoryArray(secondmaxweights, nnegcliques);
    7496
    7497 /* resort variables to avoid quadratic algorithm later on */
    7498 SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
    7499
    7500 /* save the end positions of the cliques because start positions are moved in the following loop */
    7501 for( c = 0; c < nnegcliques; ++c )
    7502 {
    7503 cliqueendposs[c] = cliquestartposs[c+1] - 1;
    7504 assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
    7505 }
    7506
    7507 c = 0;
    7508 foundmax = FALSE;
    7509 i = 0;
    7510
    7511 while( i < nvars )
    7512 {
    7513 /* ignore variables of the negated clique which are fixed to one since these are counted in
    7514 * consdata->onesweightsum
    7515 */
    7516
    7517 /* if there are only one variable negated cliques left we can stop */
    7518 if( nnegcliques - c == nvars - i )
    7519 {
    7520 minweightsum += localminweightsum;
    7521 localminweightsum = 0;
    7522 break;
    7523 }
    7524
    7525 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
    7526 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
    7527 * other clique variables to one
    7528 */
    7529 if( cliquestartposs[c] == i )
    7530 {
    7531 assert(myweights[i] > 0);
    7532 ++c;
    7533 minweightsum += localminweightsum;
    7534 localminweightsum = 0;
    7535 foundmax = TRUE;
    7536
    7537 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
    7538 foundmax = FALSE;
    7539
    7540 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
    7541 {
    7542 ++i;
    7543 continue;
    7544 }
    7545 }
    7546
    7547 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
    7548 {
    7549 assert(myweights[i] > 0);
    7550
    7551 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
    7552 {
    7553 assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
    7554
    7555 if( !foundmax )
    7556 {
    7557 foundmax = TRUE;
    7558
    7559 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
    7560 cliquestartposs[c - 1] = i;
    7561 ++i;
    7562
    7563 continue;
    7564 }
    7565 /* memorize second max weight for each clique */
    7566 if( secondmaxweights[c - 1] == 0 )
    7567 secondmaxweights[c - 1] = myweights[i];
    7568
    7569 localminweightsum += myweights[i];
    7570 }
    7571 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
    7572 else
    7573 {
    7574 int v;
    7575 /* fix all other variables of the negated clique to 1 */
    7576 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
    7577 {
    7578 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
    7579 {
    7580 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
    7581 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
    7582
    7583 if( infeasible )
    7584 {
    7585 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
    7586
    7587 /* analyze the infeasibility if conflict analysis is applicable */
    7589 {
    7590 /* conflict analysis can only be applied in solving stage */
    7592
    7593 /* initialize the conflict analysis */
    7595
    7596 /* add the two variables which are fixed to zero within a negated clique */
    7597 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
    7598 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
    7599
    7600 /* start the conflict analysis */
    7602 }
    7603 *cutoff = TRUE;
    7604 break;
    7605 }
    7606 assert(tightened);
    7607 ++(*nfixedvars);
    7609 }
    7610 }
    7611
    7612 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
    7613 localminweightsum = 0;
    7614 /* we can jump to the end of this clique */
    7615 i = cliqueendposs[c - 1];
    7616
    7617 if( *cutoff )
    7618 break;
    7619 }
    7620 }
    7621 ++i;
    7622 }
    7623 /* add last clique minweightsum */
    7624 minweightsum += localminweightsum;
    7625
    7626 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
    7627 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
    7628
    7629 /* check, if weights of fixed variables don't exceeds knapsack capacity */
    7630 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
    7631 {
    7632 SCIP_Longint maxcliqueweight = -1LL;
    7633
    7634 /* loop over cliques */
    7635 for( c = 0; c < nnegcliques; ++c )
    7636 {
    7637 SCIP_VAR* maxvar;
    7638 SCIP_Bool maxvarfixed;
    7639 int endvarposclique;
    7640 int startvarposclique;
    7641
    7642 assert(myvars != NULL);
    7643 assert(nnegcliques == consdata->nnegcliques);
    7644 assert(myweights != NULL);
    7645 assert(secondmaxweights != NULL);
    7646 assert(cliquestartposs != NULL);
    7647
    7648 endvarposclique = cliqueendposs[c];
    7649 startvarposclique = cliquestartposs[c];
    7650
    7651 maxvar = myvars[startvarposclique];
    7652
    7653 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
    7654 if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
    7655 continue;
    7656
    7657 maxcliqueweight = myweights[startvarposclique];
    7658 maxvarfixed = FALSE;
    7659 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
    7660 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
    7661 * exceeds the capacity the maximum weight variable can be fixed to zero.
    7662 */
    7663 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
    7664 {
    7665#ifndef NDEBUG
    7666 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
    7667#endif
    7668 assert(maxcliqueweight >= secondmaxweights[c]);
    7669 assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
    7670
    7671 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
    7673 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
    7674 assert(consdata->onesweightsum == oldonesweightsum);
    7675 assert(!infeasible);
    7676 assert(tightened);
    7677 (*nfixedvars)++;
    7678 maxvarfixed = TRUE;
    7679 }
    7680 /* the remaining cliques are singletons such that all subsequent variables have a weight that
    7681 * fits into the knapsack
    7682 */
    7683 else if( nnegcliques - c == nvars - startvarposclique )
    7684 break;
    7685 /* early termination of the remaining loop because no further variable fixings are possible:
    7686 *
    7687 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
    7688 * largest was set to 0) does not suffice to infer additional variable fixings because
    7689 *
    7690 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
    7691 * - their second largest elements are at least as large as the smallest weight of the knapsack
    7692 */
    7693 else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
    7694 break;
    7695
    7696 /* loop over items with non-maximal weight (omitting the first position) */
    7697 for( i = endvarposclique; i > startvarposclique; --i )
    7698 {
    7699 /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
    7700 * messed up the clique preprocessing in the previous loop to filter those variables out */
    7701 assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
    7702
    7703 /* only check variables of negated cliques for which no variable is locally fixed */
    7704 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
    7705 {
    7706 assert(maxcliqueweight >= myweights[i]);
    7707 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
    7708
    7709 /* we fix the members of this clique with non-maximal weight in two cases to 1:
    7710 *
    7711 * the maxvar was already fixed to 0 because it has a huge gain.
    7712 *
    7713 * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
    7714 * since replacing i with the element of maximal weight leads to infeasibility */
    7715 if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
    7716 {
    7717#ifndef NDEBUG
    7718 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
    7719#endif
    7720 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
    7721 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
    7722 assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
    7723 assert(!infeasible);
    7724 assert(tightened);
    7725 ++(*nfixedvars);
    7727
    7728 /* update minweightsum because now the variable is fixed to one and its weight is counted by
    7729 * consdata->onesweightsum
    7730 */
    7731 minweightsum -= myweights[i];
    7732 assert(minweightsum >= 0);
    7733 }
    7734 else
    7735 break;
    7736 }
    7737 }
    7738#ifndef NDEBUG
    7739 /* in debug mode, we assert that we did not miss possible fixings by the break above */
    7740 for( ; i > startvarposclique; --i )
    7741 {
    7742 SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
    7743 SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
    7744
    7745 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
    7746 assert(varisfixed || !exceedscapacity);
    7747 }
    7748#endif
    7749 }
    7750 }
    7751 SCIPfreeBufferArray(scip, &secondmaxweights);
    7752 SCIPfreeBufferArray(scip, &cliqueendposs);
    7753 SCIPfreeBufferArray(scip, &cliquestartposs);
    7754 SCIPfreeBufferArray(scip, &myweights);
    7755 SCIPfreeBufferArray(scip, &myvars);
    7756 }
    7757
    7758 assert(consdata->negcliquepartitioned || minweightsum == 0);
    7759 }
    7760 while( FALSE );
    7761
    7762 assert(usenegatedclique || minweightsum == 0);
    7763 /* check, if weights of fixed variables already exceed knapsack capacity */
    7764 if( consdata->capacity < minweightsum + consdata->onesweightsum )
    7765 {
    7766 SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
    7767 consdata->onesweightsum, consdata->capacity);
    7768
    7770 *cutoff = TRUE;
    7771
    7772 /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
    7774 {
    7775 /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
    7776 SCIP_Longint weight;
    7777
    7778 weight = 0;
    7779
    7781
    7782 for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
    7783 {
    7784 if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
    7785 {
    7786 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
    7787 weight += consdata->weights[i];
    7788 }
    7789 }
    7790
    7792 }
    7793
    7794 return SCIP_OKAY;
    7795 }
    7796
    7797 /* the algorithm below is a special case of propagation involving negated cliques */
    7798 if( !usenegatedclique )
    7799 {
    7800 assert(consdata->sorted);
    7801 residualcapacity = consdata->capacity - consdata->onesweightsum;
    7802
    7803 /* fix all variables to zero, that don't fit into the knapsack anymore */
    7804 for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
    7805 {
    7806 /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
    7807 * to zero
    7808 */
    7809 if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
    7810 {
    7811 if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
    7812 {
    7813 assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
    7814 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
    7816 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
    7817 assert(!infeasible);
    7818 assert(tightened);
    7819 (*nfixedvars)++;
    7820 }
    7821 }
    7822 }
    7823 }
    7824
    7825 /* check if the knapsack is now redundant */
    7826 if( !SCIPconsIsModifiable(cons) )
    7827 {
    7828 SCIP_Longint unfixedweightsum = consdata->onesweightsum;
    7829
    7830 /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
    7831 for( i = 0; i < nvars; ++i )
    7832 {
    7833 if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
    7834 {
    7835 unfixedweightsum += consdata->weights[i];
    7836
    7837 /* the weight sum is larger than the capacity, so the constraint is not redundant */
    7838 if( unfixedweightsum > consdata->capacity )
    7839 return SCIP_OKAY;
    7840 }
    7841 }
    7842 /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
    7843 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
    7844 SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
    7846 *redundant = TRUE;
    7847 }
    7848
    7849 return SCIP_OKAY;
    7850}
    7851
    7852/** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
    7853 * containing all negated variables of this knapsack constraint
    7854 */
    7855static
    7857 SCIP* scip, /**< SCIP data structure */
    7858 SCIP_CONS* cons, /**< knapsack constraint */
    7859 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    7860 int* naddconss /**< pointer to count number of added constraints */
    7861 )
    7862{
    7863 SCIP_CONS* newcons;
    7864 SCIP_CONSDATA* consdata;
    7865
    7866 assert(scip != NULL);
    7867 assert(cons != NULL);
    7868 assert(ndelconss != NULL);
    7869 assert(naddconss != NULL);
    7870
    7871 consdata = SCIPconsGetData(cons);
    7872 assert(consdata != NULL);
    7873 assert(consdata->nvars > 1);
    7874
    7875 /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
    7876 if( consdata->nvars == 2 )
    7877 {
    7878 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
    7879
    7880 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
    7884 SCIPconsIsStickingAtNode(cons)) );
    7885 }
    7886 /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
    7887 * containing all negated variables of the knapsack
    7888 */
    7889 else
    7890 {
    7891 SCIP_VAR** consvars;
    7892
    7893 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
    7894
    7895 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
    7896 SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
    7897
    7898 SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
    7902 SCIPconsIsStickingAtNode(cons)) );
    7903
    7904 SCIPfreeBufferArray(scip, &consvars);
    7905 }
    7906
    7907 /* add the upgraded constraint to the problem */
    7908 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
    7909 ++(*naddconss);
    7910
    7911 /* remove the underlying constraint from the problem */
    7912 SCIP_CALL( SCIPdelCons(scip, cons) );
    7913 ++(*ndelconss);
    7914
    7915 return SCIP_OKAY;
    7916}
    7917
    7918/** delete redundant variables
    7919 *
    7920 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
    7921 *
    7922 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
    7923 * => x4, x5 always fits into the knapsack, so we can delete them
    7924 *
    7925 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
    7926 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
    7927 */
    7928static
    7930 SCIP* scip, /**< SCIP data structure */
    7931 SCIP_CONS* cons, /**< knapsack constraint */
    7932 SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
    7933 int splitpos, /**< split position till when all front items are fitting, splitpos is the
    7934 * first which did not fit */
    7935 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
    7936 int* nchgsides, /**< pointer to store the amount of changed sides */
    7937 int* naddconss /**< pointer to count number of added constraints */
    7938 )
    7939{
    7940 SCIP_CONSHDLRDATA* conshdlrdata;
    7941 SCIP_CONSDATA* consdata;
    7942 SCIP_VAR** vars;
    7943 SCIP_Longint* weights;
    7944 SCIP_Longint capacity;
    7945 SCIP_Longint gcd;
    7946 int nvars;
    7947 int w;
    7948
    7949 assert(scip != NULL);
    7950 assert(cons != NULL);
    7951 assert(nchgcoefs != NULL);
    7952 assert(nchgsides != NULL);
    7953 assert(naddconss != NULL);
    7954
    7955 consdata = SCIPconsGetData(cons);
    7956 assert(consdata != NULL);
    7957 assert(0 < frontsum && frontsum < consdata->weightsum);
    7958 assert(0 < splitpos && splitpos < consdata->nvars);
    7959
    7960 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    7961 assert(conshdlrdata != NULL);
    7962
    7963 vars = consdata->vars;
    7964 weights = consdata->weights;
    7965 nvars = consdata->nvars;
    7966 capacity = consdata->capacity;
    7967
    7968 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    7969 * weight must not be sorted by their index
    7970 */
    7971#ifndef NDEBUG
    7972 for( w = nvars - 1; w > 0; --w )
    7973 assert(weights[w] <= weights[w-1]);
    7974#endif
    7975
    7976 /* if there are no variables rear to splitpos, the constraint has no redundant variables */
    7977 if( consdata->nvars - 1 == splitpos )
    7978 return SCIP_OKAY;
    7979
    7980 assert(frontsum + weights[splitpos] > capacity);
    7981
    7982 /* detect redundant variables */
    7983 if( consdata->weightsum - weights[splitpos] <= capacity )
    7984 {
    7985 /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
    7986 * fit
    7987 */
    7988 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
    7989
    7990 /* delete items and update capacity */
    7991 for( w = nvars - 1; w > splitpos; --w )
    7992 {
    7993 consdata->capacity -= weights[w];
    7994 SCIP_CALL( delCoefPos(scip, cons, w) );
    7995 }
    7996 assert(w == splitpos);
    7997
    7998 ++(*nchgsides);
    7999 *nchgcoefs += (nvars - splitpos);
    8000
    8001 /* division by greatest common divisor */
    8002 gcd = weights[w];
    8003 for( ; w >= 0 && gcd > 1; --w )
    8004 {
    8005 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
    8006 }
    8007
    8008 /* normalize if possible */
    8009 if( gcd > 1 )
    8010 {
    8011 for( w = splitpos; w >= 0; --w )
    8012 {
    8013 consdataChgWeight(consdata, w, weights[w]/gcd);
    8014 }
    8015 (*nchgcoefs) += nvars;
    8016
    8017 consdata->capacity /= gcd;
    8018 ++(*nchgsides);
    8019 }
    8020
    8021 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8022 * weight must not be sorted by their index
    8023 */
    8024#ifndef NDEBUG
    8025 for( w = consdata->nvars - 1; w > 0; --w )
    8026 assert(weights[w] <= weights[w - 1]);
    8027#endif
    8028 }
    8029 /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
    8030 * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
    8031 * splitpos and needs to fit into the knapsack
    8032 */
    8033 else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
    8034 {
    8035 int* clqpart;
    8036 int nclq;
    8037 int len;
    8038
    8039 len = nvars - (splitpos + 1);
    8040 /* allocate temporary memory */
    8041 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
    8042
    8043 /* calculate clique partition */
    8044 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
    8045
    8046 /* check if we found at least one clique */
    8047 if( nclq < len )
    8048 {
    8049 SCIP_Longint maxactduetoclq;
    8050 int cliquenum;
    8051
    8052 maxactduetoclq = 0;
    8053 cliquenum = 0;
    8054
    8055 /* calculate maximum activity due to cliques */
    8056 for( w = 0; w < len; ++w )
    8057 {
    8058 assert(clqpart[w] >= 0 && clqpart[w] <= w);
    8059 if( clqpart[w] == cliquenum )
    8060 {
    8061 maxactduetoclq += weights[w + splitpos + 1];
    8062 ++cliquenum;
    8063 }
    8064 }
    8065
    8066 /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
    8067 * so delete them and create for all clique the corresponding clique constraints and update the capacity
    8068 */
    8069 if( frontsum + maxactduetoclq <= capacity )
    8070 {
    8071 SCIP_VAR** clqvars;
    8072 int nclqvars;
    8073 int c;
    8074
    8075 assert(maxactduetoclq < weights[splitpos]);
    8076
    8077 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
    8078
    8079 /* allocate temporary memory */
    8080 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
    8081
    8082 for( c = 0; c < nclq; ++c )
    8083 {
    8084 nclqvars = 0;
    8085 for( w = 0; w < len; ++w )
    8086 {
    8087 if( clqpart[w] == c )
    8088 {
    8089 clqvars[nclqvars] = vars[w + splitpos + 1];
    8090 ++nclqvars;
    8091 }
    8092 }
    8093
    8094 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
    8095 if( nclqvars > 1 )
    8096 {
    8097 SCIP_CONS* cliquecons;
    8098 char name[SCIP_MAXSTRLEN];
    8099
    8100 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
    8101 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
    8105 SCIPconsIsStickingAtNode(cons)) );
    8106
    8107 /* add the special constraint to the problem */
    8108 SCIPdebugMsg(scip, " -> adding clique constraint: ");
    8109 SCIPdebugPrintCons(scip, cliquecons, NULL);
    8110 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    8111 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    8112 ++(*naddconss);
    8113 }
    8114 }
    8115
    8116 /* delete items and update capacity */
    8117 for( w = nvars - 1; w > splitpos; --w )
    8118 {
    8119 SCIP_CALL( delCoefPos(scip, cons, w) );
    8120 ++(*nchgcoefs);
    8121 }
    8122 consdata->capacity -= maxactduetoclq;
    8123 assert(frontsum <= consdata->capacity);
    8124 ++(*nchgsides);
    8125
    8126 assert(w == splitpos);
    8127
    8128 /* renew weights pointer */
    8129 weights = consdata->weights;
    8130
    8131 /* division by greatest common divisor */
    8132 gcd = weights[w];
    8133 for( ; w >= 0 && gcd > 1; --w )
    8134 {
    8135 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
    8136 }
    8137
    8138 /* normalize if possible */
    8139 if( gcd > 1 )
    8140 {
    8141 for( w = splitpos; w >= 0; --w )
    8142 {
    8143 consdataChgWeight(consdata, w, weights[w]/gcd);
    8144 }
    8145 (*nchgcoefs) += nvars;
    8146
    8147 consdata->capacity /= gcd;
    8148 ++(*nchgsides);
    8149 }
    8150
    8151 /* free temporary memory */
    8152 SCIPfreeBufferArray(scip, &clqvars);
    8153
    8154 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8155 * weight must not be sorted by their index
    8156 */
    8157#ifndef NDEBUG
    8158 for( w = consdata->nvars - 1; w > 0; --w )
    8159 assert(weights[w] <= weights[w - 1]);
    8160#endif
    8161 }
    8162 }
    8163
    8164 /* free temporary memory */
    8165 SCIPfreeBufferArray(scip, &clqpart);
    8166 }
    8167
    8168 return SCIP_OKAY;
    8169}
    8170
    8171/* detect redundant variables which always fits into the knapsack
    8172 *
    8173 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
    8174 *
    8175 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
    8176 * => x4, x5 always fits into the knapsack, so we can delete them
    8177 *
    8178 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
    8179 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
    8180 */
    8181static
    8183 SCIP* scip, /**< SCIP data structure */
    8184 SCIP_CONS* cons, /**< knapsack constraint */
    8185 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    8186 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
    8187 int* nchgsides, /**< pointer to store the amount of changed sides */
    8188 int* naddconss /**< pointer to count number of added constraints */
    8189 )
    8190{
    8191 SCIP_CONSHDLRDATA* conshdlrdata;
    8192 SCIP_CONSDATA* consdata;
    8193 SCIP_VAR** vars;
    8194 SCIP_Longint* weights;
    8195 SCIP_Longint capacity;
    8196 SCIP_Longint sum;
    8197 int nvars;
    8198 int v;
    8199 int w;
    8200
    8201 assert(scip != NULL);
    8202 assert(cons != NULL);
    8203 assert(ndelconss != NULL);
    8204 assert(nchgcoefs != NULL);
    8205 assert(nchgsides != NULL);
    8206 assert(naddconss != NULL);
    8207
    8208 consdata = SCIPconsGetData(cons);
    8209 assert(consdata != NULL);
    8210 assert(consdata->nvars >= 2);
    8211 assert(consdata->weightsum > consdata->capacity);
    8212
    8213 vars = consdata->vars;
    8214 weights = consdata->weights;
    8215 nvars = consdata->nvars;
    8216 capacity = consdata->capacity;
    8217 sum = 0;
    8218
    8219 /* search for maximal fitting items */
    8220 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
    8221 sum += weights[v];
    8222
    8223 assert(v < nvars);
    8224
    8225 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
    8226 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == nvars - 1 )
    8227 {
    8228 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8229 assert(SCIPconsIsDeleted(cons));
    8230
    8231 return SCIP_OKAY;
    8232 }
    8233
    8234 if( v < nvars - 1 )
    8235 {
    8236 /* try to delete variables */
    8237 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
    8238 assert(consdata->nvars > 1);
    8239
    8240 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
    8241 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == consdata->nvars - 1 )
    8242 {
    8243 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8244 assert(SCIPconsIsDeleted(cons));
    8245 }
    8246
    8247 return SCIP_OKAY;
    8248 }
    8249
    8250 assert(vars == consdata->vars);
    8251 assert(weights == consdata->weights);
    8252 assert(nvars == consdata->nvars);
    8253 assert(capacity == consdata->capacity);
    8254
    8255 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    8256 assert(conshdlrdata != NULL);
    8257 /* calculate clique partition */
    8258 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
    8259
    8260 /* check for real existing cliques */
    8261 if( consdata->cliquepartition[v] < v )
    8262 {
    8263 SCIP_Longint sumfront;
    8264 SCIP_Longint maxactduetoclqfront;
    8265 int* clqpart;
    8266 int cliquenum;
    8267
    8268 sumfront = 0;
    8269 maxactduetoclqfront = 0;
    8270
    8271 clqpart = consdata->cliquepartition;
    8272 cliquenum = 0;
    8273
    8274 /* calculate maximal activity due to cliques */
    8275 for( w = 0; w < nvars; ++w )
    8276 {
    8277 assert(clqpart[w] >= 0 && clqpart[w] <= w);
    8278 if( clqpart[w] == cliquenum )
    8279 {
    8280 if( maxactduetoclqfront + weights[w] <= capacity )
    8281 {
    8282 maxactduetoclqfront += weights[w];
    8283 ++cliquenum;
    8284 }
    8285 else
    8286 break;
    8287 }
    8288 sumfront += weights[w];
    8289 }
    8290 assert(w >= v);
    8291
    8292 /* if all items fit, then delete the whole constraint but create clique constraints which led to this
    8293 * information
    8294 */
    8295 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0 && w == nvars )
    8296 {
    8297 SCIP_VAR** clqvars;
    8298 int nclqvars;
    8299 int c;
    8300 int ncliques;
    8301
    8302 assert(maxactduetoclqfront <= capacity);
    8303
    8304 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
    8305
    8306 ncliques = consdata->ncliques;
    8307
    8308 /* allocate temporary memory */
    8309 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
    8310
    8311 for( c = 0; c < ncliques; ++c )
    8312 {
    8313 nclqvars = 0;
    8314 for( w = 0; w < nvars; ++w )
    8315 {
    8316 if( clqpart[w] == c )
    8317 {
    8318 clqvars[nclqvars] = vars[w];
    8319 ++nclqvars;
    8320 }
    8321 }
    8322
    8323 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
    8324 if( nclqvars > 1 )
    8325 {
    8326 SCIP_CONS* cliquecons;
    8327 char name[SCIP_MAXSTRLEN];
    8328
    8329 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
    8330 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
    8334 SCIPconsIsStickingAtNode(cons)) );
    8335
    8336 /* add the special constraint to the problem */
    8337 SCIPdebugMsg(scip, " -> adding clique constraint: ");
    8338 SCIPdebugPrintCons(scip, cliquecons, NULL);
    8339 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    8340 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    8341 ++(*naddconss);
    8342 }
    8343 }
    8344
    8345 /* delete old constraint */
    8346 SCIP_CALL( SCIPdelCons(scip, cons) );
    8347 ++(*ndelconss);
    8348
    8349 SCIPfreeBufferArray(scip, &clqvars);
    8350
    8351 return SCIP_OKAY;
    8352 }
    8353
    8354 if( w > v && w < nvars - 1 )
    8355 {
    8356 /* try to delete variables */
    8357 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
    8358 }
    8359 }
    8360
    8361 return SCIP_OKAY;
    8362}
    8363
    8364/** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
    8365static
    8367 SCIP_CONS* cons, /**< knapsack constraint */
    8368 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    8369 int* nchgsides /**< pointer to count number of side changes */
    8370 )
    8371{
    8372 SCIP_CONSDATA* consdata;
    8373 SCIP_Longint gcd;
    8374 int i;
    8375
    8376 assert(nchgcoefs != NULL);
    8377 assert(nchgsides != NULL);
    8378 assert(!SCIPconsIsModifiable(cons));
    8379
    8380 consdata = SCIPconsGetData(cons);
    8381 assert(consdata != NULL);
    8382 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
    8383 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
    8384 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
    8385 assert(consdata->nvars >= 1);
    8386
    8387 /* sort items, because we can stop earlier if the smaller weights are evaluated first */
    8388 sortItems(consdata);
    8389
    8390 gcd = consdata->weights[consdata->nvars-1];
    8391 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
    8392 {
    8393 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
    8394 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
    8395
    8396 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
    8397 }
    8398
    8399 if( gcd >= 2 )
    8400 {
    8401 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
    8402
    8403 for( i = 0; i < consdata->nvars; ++i )
    8404 {
    8405 consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
    8406 }
    8407 consdata->capacity /= gcd;
    8408 (*nchgcoefs) += consdata->nvars;
    8409 (*nchgsides)++;
    8410
    8411 /* weight should still be sorted, because the reduction preserves this */
    8412#ifndef NDEBUG
    8413 for( i = consdata->nvars - 1; i > 0; --i )
    8414 assert(consdata->weights[i] <= consdata->weights[i - 1]);
    8415#endif
    8416 consdata->sorted = TRUE;
    8417 }
    8418}
    8419
    8420/** dual weights tightening for knapsack constraints
    8421 *
    8422 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
    8423 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
    8424 * constraint
    8425 *
    8426 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
    8427 * these are a minimal cover, then might reduce the weights and the capacity, e.g.
    8428 *
    8429 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
    8430 *
    8431 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
    8432 *
    8433 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
    8434 *
    8435 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
    8436 *
    8437 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
    8438 */
    8439static
    8441 SCIP* scip, /**< SCIP data structure */
    8442 SCIP_CONS* cons, /**< knapsack constraint */
    8443 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    8444 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
    8445 int* nchgsides, /**< pointer to store the amount of changed sides */
    8446 int* naddconss /**< pointer to count number of added constraints */
    8447 )
    8448{
    8449 SCIP_CONSDATA* consdata;
    8450 SCIP_Longint* weights;
    8451 SCIP_Longint dualcapacity;
    8452 SCIP_Longint reductionsum;
    8453 SCIP_Longint capacity;
    8454 SCIP_Longint exceedsum;
    8455 int oldnchgcoefs;
    8456 int nvars;
    8457 int vbig;
    8458 int v;
    8459 int w;
    8460#ifndef NDEBUG
    8461 int oldnchgsides;
    8462#endif
    8463
    8464 assert(scip != NULL);
    8465 assert(cons != NULL);
    8466 assert(ndelconss != NULL);
    8467 assert(nchgcoefs != NULL);
    8468 assert(nchgsides != NULL);
    8469 assert(naddconss != NULL);
    8470
    8471 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
    8472 return SCIP_OKAY;
    8473
    8474#ifndef NDEBUG
    8475 oldnchgsides = *nchgsides;
    8476#endif
    8477
    8478 consdata = SCIPconsGetData(cons);
    8479 assert(consdata != NULL);
    8480 assert(consdata->weightsum > consdata->capacity);
    8481 assert(consdata->nvars >= 2);
    8482 assert(consdata->sorted);
    8483
    8484 /* constraint should be merged */
    8485 assert(consdata->merged);
    8486
    8487 nvars = consdata->nvars;
    8488 weights = consdata->weights;
    8489 capacity = consdata->capacity;
    8490
    8491 oldnchgcoefs = *nchgcoefs;
    8492
    8493 /* case 1. */
    8494 if( weights[nvars - 1] + weights[nvars - 2] > capacity )
    8495 {
    8496 SCIP_CONS* newcons;
    8497
    8498 /* two variable are enough to exceed the constraint, so we can update it to a set-packing
    8499 *
    8500 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
    8501 */
    8502 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
    8503
    8504 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
    8508 SCIPconsIsStickingAtNode(cons)) );
    8509
    8510 /* add the upgraded constraint to the problem */
    8511 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
    8512 ++(*naddconss);
    8513
    8514 /* remove the underlying constraint from the problem */
    8515 SCIP_CALL( SCIPdelCons(scip, cons) );
    8516 ++(*ndelconss);
    8517
    8518 return SCIP_OKAY;
    8519 }
    8520
    8521 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
    8522 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
    8523 {
    8524 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8525 assert(SCIPconsIsDeleted(cons));
    8526
    8527 return SCIP_OKAY;
    8528 }
    8529
    8530 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
    8531 /* @todo might be changed/removed when improving the coeffcients tightening */
    8532 if( consdata->weightsum - capacity > weights[0] + weights[1] )
    8533 return SCIP_OKAY;
    8534
    8535 /* case 2. */
    8536
    8537 v = 0;
    8538
    8539 /* @todo generalize the following algorithm for several parts of the knapsack
    8540 *
    8541 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
    8542 * variables each combination is a minimal cover, some examples
    8543 *
    8544 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
    8545 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
    8546 * <=> x1 + x2 + x3 + x4 + x5 <= 3
    8547 *
    8548 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
    8549 *
    8550 */
    8551
    8552 /* determine big weights that fit only by itself */
    8553 while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
    8554 ++v;
    8555
    8556 vbig = v;
    8557 assert(vbig < nvars - 1);
    8558 exceedsum = 0;
    8559
    8560 /* determine the amount needed to exceed the capacity */
    8561 while( v < nvars && exceedsum <= capacity )
    8562 {
    8563 exceedsum += weights[v];
    8564 ++v;
    8565 }
    8566
    8567 /* if we exceeded the capacity we might reduce the weights */
    8568 if( exceedsum > capacity )
    8569 {
    8570 assert(vbig > 0 || v < nvars);
    8571
    8572 /* all small weights were needed to exceed the capacity */
    8573 if( v == nvars )
    8574 {
    8575 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
    8576 assert(newweight > 0);
    8577
    8578 /* reduce big weights */
    8579 for( v = 0; v < vbig; ++v )
    8580 {
    8581 if( weights[v] > newweight )
    8582 {
    8583 consdataChgWeight(consdata, v, newweight);
    8584 ++(*nchgcoefs);
    8585 }
    8586 }
    8587
    8588 /* reduce small weights */
    8589 for( ; v < nvars; ++v )
    8590 {
    8591 if( weights[v] > 1 )
    8592 {
    8593 consdataChgWeight(consdata, v, 1LL);
    8594 ++(*nchgcoefs);
    8595 }
    8596 }
    8597
    8598 consdata->capacity = newweight;
    8599
    8600 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8601 * weight must not be sorted by their index
    8602 */
    8603#ifndef NDEBUG
    8604 for( v = nvars - 1; v > 0; --v )
    8605 assert(weights[v] <= weights[v-1]);
    8606#endif
    8607
    8608 return SCIP_OKAY;
    8609 }
    8610 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
    8611 * small weights
    8612 */
    8613 else
    8614 {
    8615 SCIP_Longint exceedsumback = 0;
    8616 int nexceed = v - vbig;
    8617
    8618 assert(nexceed > 1);
    8619
    8620 /* determine weightsum of the same amount as before but of the smallest weight */
    8621 for( w = nvars - 1; w >= nvars - nexceed; --w )
    8622 exceedsumback += weights[w];
    8623
    8624 assert(w >= 0);
    8625
    8626 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
    8627 * combinations of all small weights
    8628 */
    8629 if( exceedsumback > capacity )
    8630 {
    8631 SCIP_Longint newweight = nexceed - 1;
    8632
    8633 /* taking out the smallest element needs to fit */
    8634 assert(exceedsumback - weights[nvars - 1] <= capacity);
    8635
    8636 /* reduce big weights */
    8637 for( v = 0; v < vbig; ++v )
    8638 {
    8639 if( weights[v] > newweight )
    8640 {
    8641 consdataChgWeight(consdata, v, newweight);
    8642 ++(*nchgcoefs);
    8643 }
    8644 }
    8645
    8646 /* reduce small weights */
    8647 for( ; v < nvars; ++v )
    8648 {
    8649 if( weights[v] > 1 )
    8650 {
    8651 consdataChgWeight(consdata, v, 1LL);
    8652 ++(*nchgcoefs);
    8653 }
    8654 }
    8655
    8656 consdata->capacity = newweight;
    8657
    8658 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8659 * weight must not be sorted by their index
    8660 */
    8661#ifndef NDEBUG
    8662 for( v = nvars - 1; v > 0; --v )
    8663 assert(weights[v] <= weights[v-1]);
    8664#endif
    8665 return SCIP_OKAY;
    8666 }
    8667 }
    8668 }
    8669 else
    8670 {
    8671 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
    8672 * not happen here
    8673 */
    8674 assert(vbig > 0 && vbig < nvars);
    8675
    8676 /* either choose a big coefficients or all other variables
    8677 *
    8678 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
    8679 *
    8680 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
    8681 * constraint to
    8682 *
    8683 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
    8684 */
    8685
    8686 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
    8687 {
    8688 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
    8689#ifndef NDEBUG
    8690 SCIP_Longint resweightsum = consdata->weightsum;
    8691
    8692 for( v = 0; v < vbig; ++v )
    8693 resweightsum -= weights[v];
    8694
    8695 assert(exceedsum == resweightsum);
    8696#endif
    8697 assert(newweight > 0);
    8698
    8699 /* reduce big weights */
    8700 for( v = 0; v < vbig; ++v )
    8701 {
    8702 if( weights[v] > newweight )
    8703 {
    8704 consdataChgWeight(consdata, v, newweight);
    8705 ++(*nchgcoefs);
    8706 }
    8707 }
    8708
    8709 /* reduce small weights */
    8710 for( ; v < nvars; ++v )
    8711 {
    8712 if( weights[v] > 1 )
    8713 {
    8714 consdataChgWeight(consdata, v, 1LL);
    8715 ++(*nchgcoefs);
    8716 }
    8717 }
    8718
    8719 consdata->capacity = newweight;
    8720
    8721 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8722 * weight must not be sorted by their index
    8723 */
    8724#ifndef NDEBUG
    8725 for( v = nvars - 1; v > 0; --v )
    8726 assert(weights[v] <= weights[v-1]);
    8727#endif
    8728 return SCIP_OKAY;
    8729 }
    8730 }
    8731
    8732 /* case 3. */
    8733
    8734 dualcapacity = consdata->weightsum - capacity;
    8735 reductionsum = 0;
    8736 v = 0;
    8737
    8738 /* reduce big weights
    8739 *
    8740 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
    8741 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
    8742 * <=> x0 + x1 + x2 + x3 <= 3
    8743 */
    8744 while( weights[v] > dualcapacity )
    8745 {
    8746 reductionsum += (weights[v] - dualcapacity);
    8747 consdataChgWeight(consdata, v, dualcapacity);
    8748 ++v;
    8749 assert(v < nvars);
    8750 }
    8751 (*nchgcoefs) += v;
    8752
    8753 /* skip weights equal to the dualcapacity, because we cannot change them */
    8754 while( v < nvars && weights[v] == dualcapacity )
    8755 ++v;
    8756
    8757 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
    8758 * after a possible removal of the last, redundant item
    8759 *
    8760 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
    8761 */
    8762 if( v >= nvars - 1 )
    8763 {
    8764 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
    8765 if( v == nvars - 1 )
    8766 {
    8767 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
    8768 }
    8769 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8770 assert(SCIPconsIsDeleted(cons));
    8771
    8772 return SCIP_OKAY;
    8773 }
    8774 /* at least two items with weight smaller than the dual capacity */
    8775 else
    8776 {
    8777 /* @todo generalize the following algorithm for more than two variables */
    8778
    8779 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
    8780 {
    8781 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
    8782 * coefficients) of all or two variables of the rest
    8783 *
    8784 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
    8785 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
    8786 * <=> 2x1 + 2x2 + x3 + x4 <= 4
    8787 *
    8788 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
    8789 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
    8790 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
    8791 *
    8792 */
    8793 if( v > 0 && weights[nvars - 2] > 1 )
    8794 {
    8795 int ncoefchg = 0;
    8796
    8797 /* reduce all bigger weights */
    8798 for( w = 0; w < v; ++w )
    8799 {
    8800 if( weights[w] > 2 )
    8801 {
    8802 consdataChgWeight(consdata, w, 2LL);
    8803 ++ncoefchg;
    8804 }
    8805 else
    8806 {
    8807 assert(weights[0] == 2);
    8808 assert(weights[v - 1] == 2);
    8809 break;
    8810 }
    8811 }
    8812
    8813 /* reduce all smaller weights */
    8814 for( w = v; w < nvars; ++w )
    8815 {
    8816 if( weights[w] > 1 )
    8817 {
    8818 consdataChgWeight(consdata, w, 1LL);
    8819 ++ncoefchg;
    8820 }
    8821 }
    8822 assert(ncoefchg > 0);
    8823
    8824 (*nchgcoefs) += ncoefchg;
    8825
    8826 /* correct the capacity */
    8827 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
    8828 assert(consdata->capacity > 0);
    8829 assert(weights[0] <= consdata->capacity);
    8830 assert(consdata->weightsum > consdata->capacity);
    8831 /* reset the reductionsum */
    8832 reductionsum = 0;
    8833 }
    8834 else if( v == 0 )
    8835 {
    8836 assert(weights[nvars - 2] == 1);
    8837 }
    8838 }
    8839 else
    8840 {
    8841 SCIP_Longint minweight = weights[nvars - 1];
    8842 SCIP_Longint newweight = dualcapacity - minweight;
    8843 SCIP_Longint restsumweights = 0;
    8844 SCIP_Longint sumcoef;
    8845 SCIP_Bool sumcoefcase = FALSE;
    8846 int startv = v;
    8847 int end;
    8848 int k;
    8849
    8850 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
    8851
    8852 /* reduce big weights of pairs that exceed the dualcapacity
    8853 *
    8854 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
    8855 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
    8856 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
    8857 */
    8858 while( weights[v] > newweight )
    8859 {
    8860 reductionsum += (weights[v] - newweight);
    8861 consdataChgWeight(consdata, v, newweight);
    8862 ++v;
    8863 assert(v < nvars);
    8864 }
    8865 (*nchgcoefs) += (v - startv);
    8866
    8867 /* skip equal weights */
    8868 while( weights[v] == newweight )
    8869 ++v;
    8870
    8871 if( v > 0 )
    8872 {
    8873 for( w = v; w < nvars; ++w )
    8874 restsumweights += weights[w];
    8875 }
    8876 else
    8877 restsumweights = consdata->weightsum;
    8878
    8879 if( restsumweights < dualcapacity )
    8880 {
    8881 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
    8882 *
    8883 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
    8884 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
    8885 */
    8886 if( startv == v )
    8887 {
    8888 /* remove redundant variables */
    8889 for( w = nvars - 1; w >= v; --w )
    8890 {
    8891 SCIP_CALL( delCoefPos(scip, cons, v) );
    8892 ++(*nchgcoefs);
    8893 }
    8894
    8895#ifndef NDEBUG
    8896 /* each coefficients should exceed the dualcapacity by itself */
    8897 for( ; w >= 0; --w )
    8898 assert(weights[w] == dualcapacity);
    8899#endif
    8900 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
    8901 * upgrade this constraint
    8902 */
    8903 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
    8904 assert(SCIPconsIsDeleted(cons));
    8905
    8906 return SCIP_OKAY;
    8907 }
    8908
    8909 /* special case where we have three different coefficient types
    8910 *
    8911 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
    8912 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
    8913 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
    8914 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
    8915 */
    8916 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
    8917 {
    8918 SCIP_Longint newcap;
    8919
    8920 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
    8921 for( w = nvars - 1; w >= v; --w )
    8922 {
    8923 if( weights[w] > 1 )
    8924 {
    8925 consdataChgWeight(consdata, w, 1LL);
    8926 ++(*nchgcoefs);
    8927 }
    8928 }
    8929
    8930 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
    8931 * dualcapacity
    8932 */
    8933 newweight = (SCIP_Longint)nvars - v;
    8934 assert(newweight > 1);
    8935 for( ; w >= startv; --w )
    8936 {
    8937 if( weights[w] > newweight )
    8938 {
    8939 consdataChgWeight(consdata, w, newweight);
    8940 ++(*nchgcoefs);
    8941 }
    8942 else
    8943 assert(weights[w] == newweight);
    8944 }
    8945
    8946 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
    8947 ++newweight;
    8948 assert(newweight > 2);
    8949 for( ; w >= 0; --w )
    8950 {
    8951 if( weights[w] > newweight )
    8952 {
    8953 consdataChgWeight(consdata, w, newweight);
    8954 ++(*nchgcoefs);
    8955 }
    8956 else
    8957 assert(weights[w] == newweight);
    8958 }
    8959
    8960 /* update the capacity */
    8961 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
    8962 if( consdata->capacity > newcap )
    8963 {
    8964 consdata->capacity = newcap;
    8965 ++(*nchgsides);
    8966 }
    8967 else
    8968 assert(consdata->capacity == newcap);
    8969 }
    8970 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
    8971
    8972 /* the new dualcapacity should still be equal to the (nvars - v + 1) */
    8973 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
    8974
    8975 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    8976 * weight must not be sorted by their index
    8977 */
    8978#ifndef NDEBUG
    8979 for( w = nvars - 1; w > 0; --w )
    8980 assert(weights[w] <= weights[w - 1]);
    8981#endif
    8982 return SCIP_OKAY;
    8983 }
    8984
    8985 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
    8986 end = nvars - 2;
    8987 while( end >= 0 && weights[end] == weights[end + 1] )
    8988 {
    8989 assert(end >= v);
    8990 --end;
    8991 }
    8992
    8993 if( v >= end )
    8994 goto TERMINATE;
    8995
    8996 end = nvars - 2;
    8997
    8998 /* can we stop early, another special reduction case might exist */
    8999 if( 2 * weights[end] > dualcapacity )
    9000 {
    9001 restsumweights = 0;
    9002
    9003 /* determine capacity of the small items */
    9004 for( w = end + 1; w < nvars; ++w )
    9005 restsumweights += weights[w];
    9006
    9007 if( restsumweights * 2 <= dualcapacity )
    9008 {
    9009 /* check for further posssible reductions in the middle */
    9010 while( v < end && restsumweights + weights[v] >= dualcapacity )
    9011 ++v;
    9012
    9013 if( v >= end )
    9014 goto TERMINATE;
    9015
    9016 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
    9017 if( (dualcapacity & 1) == 0 )
    9018 {
    9019 newweight = dualcapacity / 2;
    9020
    9021 /* set all middle coefficients */
    9022 for( ; v <= end; ++v )
    9023 {
    9024 if( weights[v] > newweight )
    9025 {
    9026 reductionsum += (weights[v] - newweight);
    9027 consdataChgWeight(consdata, v, newweight);
    9028 ++(*nchgcoefs);
    9029 }
    9030 }
    9031 }
    9032 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
    9033 * other coefficients by 2
    9034 */
    9035 else
    9036 {
    9037 /* correct the reductionsum */
    9038 reductionsum *= 2;
    9039
    9040 /* multiply big coefficients by 2 */
    9041 for( w = 0; w < v; ++w )
    9042 {
    9043 consdataChgWeight(consdata, w, weights[w] * 2);
    9044 }
    9045
    9046 newweight = dualcapacity;
    9047 /* set all middle coefficients */
    9048 for( ; v <= end; ++v )
    9049 {
    9050 reductionsum += (2 * weights[v] - newweight);
    9051 consdataChgWeight(consdata, v, newweight);
    9052 }
    9053
    9054 /* multiply small coefficients by 2 */
    9055 for( w = end + 1; w < nvars; ++w )
    9056 {
    9057 consdataChgWeight(consdata, w, weights[w] * 2);
    9058 }
    9059 (*nchgcoefs) += nvars;
    9060
    9061 dualcapacity *= 2;
    9062 consdata->capacity *= 2;
    9063 ++(*nchgsides);
    9064 }
    9065 }
    9066
    9067 goto TERMINATE;
    9068 }
    9069
    9070 /* further reductions using the next possible coefficient sum
    9071 *
    9072 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
    9073 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
    9074 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
    9075 */
    9076 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
    9077 for( k = 0; k < 4; ++k )
    9078 {
    9079 /* determine next minimal coefficient sum */
    9080 switch( k )
    9081 {
    9082 case 0:
    9083 sumcoef = weights[nvars - 1] + weights[nvars - 2];
    9084 break;
    9085 case 1:
    9086 assert(nvars >= 3);
    9087 sumcoef = weights[nvars - 1] + weights[nvars - 3];
    9088 break;
    9089 case 2:
    9090 assert(nvars >= 4);
    9091 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
    9092 {
    9093 sumcoefcase = TRUE;
    9094 sumcoef = weights[nvars - 1] + weights[nvars - 4];
    9095 }
    9096 else
    9097 {
    9098 sumcoefcase = FALSE;
    9099 sumcoef = weights[nvars - 2] + weights[nvars - 3];
    9100 }
    9101 break;
    9102 case 3:
    9103 assert(nvars >= 5);
    9104 if( sumcoefcase )
    9105 {
    9106 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
    9107 }
    9108 else
    9109 {
    9110 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
    9111 }
    9112 break;
    9113 default:
    9114 return SCIP_ERROR;
    9115 }
    9116
    9117 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
    9118 minweight = weights[end];
    9119 while( minweight <= sumcoef )
    9120 {
    9121 newweight = dualcapacity - minweight;
    9122 startv = v;
    9123 assert(v < nvars);
    9124
    9125 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
    9126 /* shrink big coefficients */
    9127 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
    9128 {
    9129 reductionsum += (weights[v] - newweight);
    9130 consdataChgWeight(consdata, v, newweight);
    9131 ++v;
    9132 assert(v < nvars);
    9133 }
    9134 (*nchgcoefs) += (v - startv);
    9135
    9136 /* skip unchangable weights */
    9137 while( weights[v] + minweight == dualcapacity )
    9138 {
    9139 assert(v < nvars);
    9140 ++v;
    9141 }
    9142
    9143 --end;
    9144 /* skip same end weights */
    9145 while( end >= 0 && weights[end] == weights[end + 1] )
    9146 --end;
    9147
    9148 if( v >= end )
    9149 goto TERMINATE;
    9150
    9151 minweight = weights[end];
    9152 }
    9153
    9154 if( v >= end )
    9155 goto TERMINATE;
    9156
    9157 /* now check if a combination of small coefficients allows us to tighten big coefficients further */
    9158 if( sumcoef < minweight )
    9159 {
    9160 minweight = sumcoef;
    9161 newweight = dualcapacity - minweight;
    9162 startv = v;
    9163 assert(v < nvars);
    9164
    9165 /* shrink big coefficients */
    9166 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
    9167 {
    9168 reductionsum += (weights[v] - newweight);
    9169 consdataChgWeight(consdata, v, newweight);
    9170 ++v;
    9171 assert(v < nvars);
    9172 }
    9173 (*nchgcoefs) += (v - startv);
    9174
    9175 /* skip unchangable weights */
    9176 while( weights[v] + minweight == dualcapacity )
    9177 {
    9178 assert(v < nvars);
    9179 ++v;
    9180 }
    9181 }
    9182
    9183 if( v >= end )
    9184 goto TERMINATE;
    9185
    9186 /* can we stop early, another special reduction case might exist */
    9187 if( 2 * weights[end] > dualcapacity )
    9188 {
    9189 restsumweights = 0;
    9190
    9191 /* determine capacity of the small items */
    9192 for( w = end + 1; w < nvars; ++w )
    9193 restsumweights += weights[w];
    9194
    9195 if( restsumweights * 2 <= dualcapacity )
    9196 {
    9197 /* check for further posssible reductions in the middle */
    9198 while( v < end && restsumweights + weights[v] >= dualcapacity )
    9199 ++v;
    9200
    9201 if( v >= end )
    9202 goto TERMINATE;
    9203
    9204 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
    9205 if( (dualcapacity & 1) == 0 )
    9206 {
    9207 newweight = dualcapacity / 2;
    9208
    9209 /* set all middle coefficients */
    9210 for( ; v <= end; ++v )
    9211 {
    9212 if( weights[v] > newweight )
    9213 {
    9214 reductionsum += (weights[v] - newweight);
    9215 consdataChgWeight(consdata, v, newweight);
    9216 ++(*nchgcoefs);
    9217 }
    9218 }
    9219 }
    9220 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
    9221 * other coefficients by 2
    9222 */
    9223 else
    9224 {
    9225 /* correct the reductionsum */
    9226 reductionsum *= 2;
    9227
    9228 /* multiply big coefficients by 2 */
    9229 for( w = 0; w < v; ++w )
    9230 {
    9231 consdataChgWeight(consdata, w, weights[w] * 2);
    9232 }
    9233
    9234 newweight = dualcapacity;
    9235 /* set all middle coefficients */
    9236 for( ; v <= end; ++v )
    9237 {
    9238 reductionsum += (2 * weights[v] - newweight);
    9239 consdataChgWeight(consdata, v, newweight);
    9240 }
    9241
    9242 /* multiply small coefficients by 2 */
    9243 for( w = end + 1; w < nvars; ++w )
    9244 {
    9245 consdataChgWeight(consdata, w, weights[w] * 2);
    9246 }
    9247 (*nchgcoefs) += nvars;
    9248
    9249 dualcapacity *= 2;
    9250 consdata->capacity *= 2;
    9251 ++(*nchgsides);
    9252 }
    9253 }
    9254
    9255 goto TERMINATE;
    9256 }
    9257
    9258 /* cannot tighten any further */
    9259 if( 2 * sumcoef > dualcapacity )
    9260 goto TERMINATE;
    9261 }
    9262 }
    9263 }
    9264
    9265 TERMINATE:
    9266 /* correct capacity */
    9267 if( reductionsum > 0 )
    9268 {
    9269 assert(v > 0);
    9270
    9271 consdata->capacity -= reductionsum;
    9272 ++(*nchgsides);
    9273
    9274 assert(consdata->weightsum - dualcapacity == consdata->capacity);
    9275 }
    9276 assert(weights[0] <= consdata->capacity);
    9277
    9278 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
    9279 * weight must not be sorted by their index
    9280 */
    9281#ifndef NDEBUG
    9282 for( w = nvars - 1; w > 0; --w )
    9283 assert(weights[w] <= weights[w - 1]);
    9284#endif
    9285
    9286 if( oldnchgcoefs < *nchgcoefs )
    9287 {
    9288 assert(!SCIPconsIsDeleted(cons));
    9289
    9290 /* it might be that we can divide the weights by their greatest common divisor */
    9291 normalizeWeights(cons, nchgcoefs, nchgsides);
    9292 }
    9293 else
    9294 {
    9295 assert(oldnchgcoefs == *nchgcoefs);
    9296 assert(oldnchgsides == *nchgsides);
    9297 }
    9298
    9299 return SCIP_OKAY;
    9300}
    9301
    9302
    9303/** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
    9304static
    9306 SCIP* scip, /**< SCIP data structure */
    9307 SCIP_CONS* cons, /**< knapsack constraint */
    9308 int* nfixedvars, /**< pointer to store the amount of fixed variables */
    9309 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    9310 int* nchgcoefs /**< pointer to store the amount of changed coefficients */
    9311 )
    9312{
    9313 SCIP_VAR** vars;
    9314 SCIP_CONSDATA* consdata;
    9315 SCIP_Longint* weights;
    9316 SCIP_Longint capacity;
    9317 SCIP_Bool infeasible;
    9318 SCIP_Bool fixed;
    9319 int nvars;
    9320 int v;
    9321
    9322 assert(scip != NULL);
    9323 assert(cons != NULL);
    9324 assert(nfixedvars != NULL);
    9325 assert(ndelconss != NULL);
    9326 assert(nchgcoefs != NULL);
    9327
    9328 consdata = SCIPconsGetData(cons);
    9329 assert(consdata != NULL);
    9330
    9331 nvars = consdata->nvars;
    9332
    9333 /* no variables left, then delete constraint */
    9334 if( nvars == 0 )
    9335 {
    9336 assert(consdata->capacity >= 0);
    9337
    9338 SCIP_CALL( SCIPdelCons(scip, cons) );
    9339 ++(*ndelconss);
    9340
    9341 return SCIP_OKAY;
    9342 }
    9343
    9344 /* sort items */
    9345 sortItems(consdata);
    9346
    9347 vars = consdata->vars;
    9348 weights = consdata->weights;
    9349 capacity = consdata->capacity;
    9350 v = 0;
    9351
    9352 /* check for weights bigger than the capacity */
    9353 while( v < nvars && weights[v] > capacity )
    9354 {
    9355 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
    9356 assert(!infeasible);
    9357
    9358 if( fixed )
    9359 ++(*nfixedvars);
    9360
    9361 ++v;
    9362 }
    9363
    9364 /* if we fixed at least one variable we need to delete them from the constraint */
    9365 if( v > 0 )
    9366 {
    9367 if( v == nvars )
    9368 {
    9369 SCIP_CALL( SCIPdelCons(scip, cons) );
    9370 ++(*ndelconss);
    9371
    9372 return SCIP_OKAY;
    9373 }
    9374
    9375 /* delete all position from back to front */
    9376 for( --v; v >= 0; --v )
    9377 {
    9378 SCIP_CALL( delCoefPos(scip, cons, v) );
    9379 ++(*nchgcoefs);
    9380 }
    9381
    9382 /* sort items again because of deletion */
    9383 sortItems(consdata);
    9384 assert(vars == consdata->vars);
    9385 assert(weights == consdata->weights);
    9386 }
    9387 assert(consdata->sorted);
    9388 assert(weights[0] <= capacity);
    9389
    9390 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
    9391 {
    9392 SCIP_CALL( SCIPdelCons(scip, cons) );
    9393 ++(*ndelconss);
    9394 }
    9395
    9396 return SCIP_OKAY;
    9397}
    9398
    9399
    9400/** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
    9401 *
    9402 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
    9403 *
    9404 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
    9405 *
    9406 * the above constraint can be changed to
    9407 *
    9408 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
    9409 *
    9410 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
    9411 *
    9412 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
    9413 *
    9414 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
    9415 * constraint further, e.g.
    9416 *
    9417 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
    9418 * => 2x1 + x2 + x3 + x4 <= 2
    9419 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
    9420 */
    9421static
    9423 SCIP* scip, /**< SCIP data structure */
    9424 SCIP_CONS* cons, /**< knapsack constraint */
    9425 int* nfixedvars, /**< pointer to store the amount of fixed variables */
    9426 int* ndelconss, /**< pointer to store the amount of deleted constraints */
    9427 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
    9428 int* nchgsides, /**< pointer to store the amount of changed sides */
    9429 int* naddconss, /**< pointer to count number of added constraints */
    9430 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
    9431 )
    9432{
    9433 SCIP_VAR** vars;
    9434 SCIP_CONSDATA* consdata;
    9435 SCIP_Longint* weights;
    9436 SCIP_Longint restweight;
    9437 SCIP_Longint newweight;
    9438 SCIP_Longint weight;
    9439 SCIP_Longint oldgcd;
    9440 SCIP_Longint rest;
    9441 SCIP_Longint gcd;
    9442 int oldnchgcoefs; /* cppcheck-suppress unassignedVariable */
    9443 int oldnchgsides; /* cppcheck-suppress unassignedVariable */
    9444 int candpos;
    9445 int candpos2;
    9446 int offsetv;
    9447 int nvars;
    9448 int v;
    9449
    9450 assert(scip != NULL);
    9451 assert(cons != NULL);
    9452 assert(nfixedvars != NULL);
    9453 assert(ndelconss != NULL);
    9454 assert(nchgcoefs != NULL);
    9455 assert(nchgsides != NULL);
    9456 assert(naddconss != NULL);
    9457 assert(cutoff != NULL);
    9458 assert(!SCIPconsIsModifiable(cons));
    9459
    9460 consdata = SCIPconsGetData(cons);
    9461 assert( consdata != NULL );
    9462
    9463 *cutoff = FALSE;
    9464
    9465 /* remove double enties and also combinations of active and negated variables */
    9466 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    9467 assert(consdata->merged);
    9468 if( *cutoff )
    9469 return SCIP_OKAY;
    9470
    9471 assert(consdata->capacity >= 0);
    9472
    9473 /* fix variables with big coefficients and remove redundant constraints, sort weights */
    9474 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
    9475
    9476 if( SCIPconsIsDeleted(cons) )
    9477 return SCIP_OKAY;
    9478
    9479 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
    9480 {
    9481 /* 1. dual weights tightening */
    9482 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
    9483
    9484 if( SCIPconsIsDeleted(cons) )
    9485 return SCIP_OKAY;
    9486 /* 2. delete redundant variables */
    9487 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
    9488
    9489 if( SCIPconsIsDeleted(cons) )
    9490 return SCIP_OKAY;
    9491 }
    9492
    9493 weights = consdata->weights;
    9494 nvars = consdata->nvars;
    9495
    9496#ifndef NDEBUG
    9497 /* constraint might not be sorted, but the weights are already sorted */
    9498 for( v = nvars - 1; v > 0; --v )
    9499 assert(weights[v] <= weights[v-1]);
    9500#endif
    9501
    9502 /* determine greatest common divisor */
    9503 gcd = weights[nvars - 1];
    9504 for( v = nvars - 2; v >= 0 && gcd > 1; --v )
    9505 {
    9506 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
    9507 }
    9508
    9509 /* divide the constraint by their greatest common divisor */
    9510 if( gcd >= 2 )
    9511 {
    9512 for( v = nvars - 1; v >= 0; --v )
    9513 {
    9514 consdataChgWeight(consdata, v, weights[v]/gcd);
    9515 }
    9516 (*nchgcoefs) += nvars;
    9517
    9518 consdata->capacity /= gcd;
    9519 (*nchgsides)++;
    9520 }
    9521 assert(consdata->nvars == nvars);
    9522
    9523 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
    9524 * must not be sorted by their index
    9525 */
    9526#ifndef NDEBUG
    9527 for( v = nvars - 1; v > 0; --v )
    9528 assert(weights[v] <= weights[v-1]);
    9529#endif
    9530
    9531 /* 3. start gcd procedure for all variables */
    9532 do
    9533 {
    9534 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
    9535 SCIPdebug( oldnchgsides = *nchgsides; )
    9536
    9537 vars = consdata->vars;
    9538 weights = consdata->weights;
    9539 nvars = consdata->nvars;
    9540
    9541 /* stop if we have two coefficients which are one in absolute value */
    9542 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
    9543 return SCIP_OKAY;
    9544
    9545 v = 0;
    9546 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
    9547 * gcd
    9548 */
    9549 while( weights[v] == consdata->capacity )
    9550 {
    9551 ++v;
    9552 assert(v < nvars);
    9553 }
    9554
    9555 /* all but one variable are as big as the capacity, this is handled elsewhere */
    9556 if( v == nvars - 1 )
    9557 return SCIP_OKAY;
    9558
    9559 offsetv = v;
    9560
    9561 gcd = -1;
    9562 candpos = -1;
    9563 candpos2 = -1;
    9564
    9565 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
    9566 * change the coefficient
    9567 */
    9568 for( v = nvars - 1; v >= offsetv; --v )
    9569 {
    9570 weight = weights[v];
    9571 assert(weight >= 1);
    9572
    9573 oldgcd = gcd;
    9574
    9575 if( gcd == -1 )
    9576 {
    9577 gcd = weights[v];
    9578 assert(gcd >= 1);
    9579 }
    9580 else
    9581 {
    9582 /* calculate greatest common divisor for all variables */
    9583 gcd = SCIPcalcGreComDiv(gcd, weight);
    9584 }
    9585
    9586 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
    9587 * can terminate
    9588 */
    9589 if( gcd == 1 )
    9590 {
    9591 /* found candidate */
    9592 if( candpos == -1 )
    9593 {
    9594 gcd = oldgcd;
    9595 candpos = v;
    9596
    9597 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
    9598 if( v == nvars - 2 )
    9599 candpos2 = v + 1;
    9600 }
    9601 /* two different variables lead to a gcd of one, so we cannot change a coefficient */
    9602 else
    9603 {
    9604 if( candpos == v + 1 && candpos2 == v + 2 )
    9605 {
    9606 assert(candpos2 == nvars - 1);
    9607
    9608 /* take new candidates */
    9609 candpos = candpos2;
    9610
    9611 /* recalculate gcd from scratch */
    9612 gcd = weights[v+1];
    9613 assert(gcd >= 1);
    9614
    9615 /* calculate greatest common divisor for variables */
    9616 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
    9617 if( gcd == 1 )
    9618 return SCIP_OKAY;
    9619 }
    9620 else
    9621 /* cannot determine a possible coefficient for reduction */
    9622 return SCIP_OKAY;
    9623 }
    9624 }
    9625 }
    9626 assert(gcd >= 2);
    9627
    9628 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
    9629 * further
    9630 */
    9631 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
    9632
    9633 /* determine the remainder of the capacity and the gcd */
    9634 rest = consdata->capacity % gcd;
    9635 assert(rest >= 0);
    9636 assert(rest < gcd);
    9637
    9638 if( candpos == -1 )
    9639 {
    9640 /* we assume that the constraint was normalized */
    9641 assert(rest > 0);
    9642
    9643 /* replace old with new capacity */
    9644 consdata->capacity -= rest;
    9645 ++(*nchgsides);
    9646
    9647 /* replace old big coefficients with new capacity */
    9648 for( v = 0; v < offsetv; ++v )
    9649 {
    9650 consdataChgWeight(consdata, v, consdata->capacity);
    9651 }
    9652
    9653 *nchgcoefs += offsetv;
    9654 goto CONTINUE;
    9655 }
    9656
    9657 /* determine the remainder of the coefficient candidate and the gcd */
    9658 restweight = weights[candpos] % gcd;
    9659 assert(restweight >= 1);
    9660 assert(restweight < gcd);
    9661
    9662 /* calculate new coefficient */
    9663 if( restweight > rest )
    9664 newweight = weights[candpos] - restweight + gcd;
    9665 else
    9666 newweight = weights[candpos] - restweight;
    9667
    9668 assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
    9669
    9670 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);
    9671
    9672 /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
    9673 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
    9674 */
    9675 if( newweight == 0 && offsetv > 0 )
    9676 return SCIP_OKAY;
    9677
    9678 if( rest > 0 )
    9679 {
    9680 /* replace old with new capacity */
    9681 consdata->capacity -= rest;
    9682 ++(*nchgsides);
    9683
    9684 /* replace old big coefficients with new capacity */
    9685 for( v = 0; v < offsetv; ++v )
    9686 {
    9687 consdataChgWeight(consdata, v, consdata->capacity);
    9688 }
    9689
    9690 *nchgcoefs += offsetv;
    9691 }
    9692
    9693 if( newweight == 0 )
    9694 {
    9695 /* delete redundant coefficient */
    9696 SCIP_CALL( delCoefPos(scip, cons, candpos) );
    9697 assert(consdata->nvars == nvars - 1);
    9698 --nvars;
    9699 }
    9700 else
    9701 {
    9702 /* replace old with new coefficient */
    9703 consdataChgWeight(consdata, candpos, newweight);
    9704 }
    9705 ++(*nchgcoefs);
    9706
    9707 assert(consdata->vars == vars);
    9708 assert(consdata->nvars == nvars);
    9709 assert(consdata->weights == weights);
    9710
    9711 CONTINUE:
    9712 /* now constraint can be normalized, dividing it by the gcd */
    9713 for( v = nvars - 1; v >= 0; --v )
    9714 {
    9715 consdataChgWeight(consdata, v, weights[v]/gcd);
    9716 }
    9717 (*nchgcoefs) += nvars;
    9718
    9719 consdata->capacity /= gcd;
    9720 ++(*nchgsides);
    9721
    9723
    9724 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));
    9725 }
    9726 while( nvars >= 2 );
    9727
    9728 return SCIP_OKAY;
    9729}
    9730
    9731
    9732/** inserts an element into the list of binary zero implications */
    9733static
    9735 SCIP* scip, /**< SCIP data structure */
    9736 int** liftcands, /**< array of the lifting candidates */
    9737 int* nliftcands, /**< number of lifting candidates */
    9738 int** firstidxs, /**< array of first zeroitems indices */
    9739 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
    9740 int** zeroitems, /**< pointer to zero items array */
    9741 int** nextidxs, /**< pointer to array of next zeroitems indeces */
    9742 int* zeroitemssize, /**< pointer to size of zero items array */
    9743 int* nzeroitems, /**< pointer to length of zero items array */
    9744 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
    9745 SCIP_Bool value, /**< value v of variable y in implication */
    9746 int knapsackidx, /**< index of variable x in knapsack */
    9747 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
    9748 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
    9749 )
    9750{
    9751 int nzeros;
    9752
    9753 assert(liftcands != NULL);
    9754 assert(liftcands[value] != NULL);
    9755 assert(nliftcands != NULL);
    9756 assert(firstidxs != NULL);
    9757 assert(firstidxs[value] != NULL);
    9758 assert(zeroweightsums != NULL);
    9759 assert(zeroweightsums[value] != NULL);
    9760 assert(zeroitems != NULL);
    9761 assert(nextidxs != NULL);
    9762 assert(zeroitemssize != NULL);
    9763 assert(nzeroitems != NULL);
    9764 assert(*nzeroitems <= *zeroitemssize);
    9765 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
    9766 assert(memlimitreached != NULL);
    9767
    9768 nzeros = *nzeroitems;
    9769
    9770 /* allocate enough memory */
    9771 if( nzeros == *zeroitemssize )
    9772 {
    9773 /* we explicitly construct the complete implication graph where the knapsack variables are involved;
    9774 * this can be too huge - abort on memory limit
    9775 */
    9776 if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
    9777 {
    9778 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
    9779 *zeroitemssize);
    9780 *memlimitreached = TRUE;
    9781 return SCIP_OKAY;
    9782 }
    9783 *zeroitemssize *= 2;
    9784 *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
    9785 SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
    9786 SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
    9787 }
    9788 assert(nzeros < *zeroitemssize);
    9789
    9790 if( *memlimitreached )
    9791 *memlimitreached = FALSE;
    9792
    9793 /* insert element */
    9794 (*zeroitems)[nzeros] = knapsackidx;
    9795 (*nextidxs)[nzeros] = firstidxs[value][probindex];
    9796 if( firstidxs[value][probindex] == 0 )
    9797 {
    9798 liftcands[value][nliftcands[value]] = probindex;
    9799 ++nliftcands[value];
    9800 }
    9801 firstidxs[value][probindex] = nzeros;
    9802 ++(*nzeroitems);
    9803 zeroweightsums[value][probindex] += knapsackweight;
    9804
    9805 return SCIP_OKAY;
    9806}
    9807
    9808#define MAX_CLIQUELENGTH 50
    9809/** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
    9810 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
    9811 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
    9812 * if cliqueweightsum(xi == v) < capacity:
    9813 * - fixing variable xi to v would make the knapsack constraint redundant
    9814 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
    9815 * redundancy effect:
    9816 * wi' := capacity - cliqueweightsum(xi == v)
    9817 * this rule can also be applied to binary variables not in the knapsack!
    9818 */
    9819static
    9821 SCIP* scip, /**< SCIP data structure */
    9822 SCIP_CONS* cons, /**< knapsack constraint */
    9823 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    9824 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
    9825 )
    9826{
    9827 SCIP_CONSDATA* consdata;
    9828 SCIP_VAR** binvars;
    9829 int nbinvars;
    9830 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
    9831 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
    9832 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
    9833 int* zeroitems; /* item number in knapsack that is implied to zero */
    9834 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
    9835 int zeroitemssize;
    9836 int nzeroitems;
    9837 SCIP_Bool* zeroiteminserted[2];
    9838 SCIP_Bool memlimitreached;
    9839 int nliftcands[2];
    9840 SCIP_Bool* cliqueused;
    9841 SCIP_Bool* itemremoved;
    9842 SCIP_Longint maxcliqueweightsum;
    9843 SCIP_VAR** addvars;
    9844 SCIP_Longint* addweights;
    9845 SCIP_Longint addweightsum;
    9846 int nvars;
    9847 int cliquenum;
    9848 int naddvars;
    9849 int val;
    9850 int i;
    9851
    9852 int* tmpindices;
    9853 SCIP_Bool* tmpboolindices;
    9854 int* tmpindices2;
    9855 SCIP_Bool* tmpboolindices2;
    9856 int* tmpindices3;
    9857 SCIP_Bool* tmpboolindices3;
    9858 int tmp;
    9859 int tmp2;
    9860 int tmp3;
    9861 SCIP_CONSHDLR* conshdlr;
    9862 SCIP_CONSHDLRDATA* conshdlrdata;
    9863
    9864 assert(nchgcoefs != NULL);
    9865 assert(!SCIPconsIsModifiable(cons));
    9866
    9867 consdata = SCIPconsGetData(cons);
    9868 assert(consdata != NULL);
    9869 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
    9870 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
    9871 assert(consdata->nvars > 0);
    9872 assert(consdata->merged);
    9873
    9874 nvars = consdata->nvars;
    9875
    9876 /* check if the knapsack has too many items/cliques for applying this costly method */
    9877 if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
    9878 return SCIP_OKAY;
    9879
    9880 /* sort items, s.t. the heaviest one is in the first position */
    9881 sortItems(consdata);
    9882
    9883 if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
    9884 return SCIP_OKAY;
    9885
    9886 /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
    9887 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
    9888 assert(nbinvars > 0);
    9889 binvars = SCIPgetVars(scip);
    9890
    9891 /* get conshdlrdata to use cleared memory */
    9892 conshdlr = SCIPconsGetHdlr(cons);
    9893 assert(conshdlr != NULL);
    9894 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9895 assert(conshdlrdata != NULL);
    9896
    9897 /* allocate temporary memory for the list of implied to zero variables */
    9898 zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
    9899 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
    9900 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
    9901
    9902 assert(conshdlrdata->ints1size > 0);
    9903 assert(conshdlrdata->ints2size > 0);
    9904 assert(conshdlrdata->longints1size > 0);
    9905 assert(conshdlrdata->longints2size > 0);
    9906
    9907 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
    9908 * than binary + integer variables existed at the presolving initialization method, but for example if you would
    9909 * transform all integers into their binary representation then it maybe happens
    9910 */
    9911 if( conshdlrdata->ints1size < nbinvars )
    9912 {
    9913 int oldsize = conshdlrdata->ints1size;
    9914
    9915 conshdlrdata->ints1size = nbinvars;
    9916 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
    9917 BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
    9918 }
    9919 if( conshdlrdata->ints2size < nbinvars )
    9920 {
    9921 int oldsize = conshdlrdata->ints2size;
    9922
    9923 conshdlrdata->ints2size = nbinvars;
    9924 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
    9925 BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
    9926 }
    9927 if( conshdlrdata->longints1size < nbinvars )
    9928 {
    9929 int oldsize = conshdlrdata->longints1size;
    9930
    9931 conshdlrdata->longints1size = nbinvars;
    9932 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
    9933 BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
    9934 }
    9935 if( conshdlrdata->longints2size < nbinvars )
    9936 {
    9937 int oldsize = conshdlrdata->longints2size;
    9938
    9939 conshdlrdata->longints2size = nbinvars;
    9940 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
    9941 BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
    9942 }
    9943
    9944 firstidxs[0] = conshdlrdata->ints1;
    9945 firstidxs[1] = conshdlrdata->ints2;
    9946 zeroweightsums[0] = conshdlrdata->longints1;
    9947 zeroweightsums[1] = conshdlrdata->longints2;
    9948
    9949 /* check for cleared arrays, all entries are zero */
    9950#ifndef NDEBUG
    9951 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
    9952 {
    9953 assert(firstidxs[0][tmp] == 0);
    9954 assert(firstidxs[1][tmp] == 0);
    9955 assert(zeroweightsums[0][tmp] == 0);
    9956 assert(zeroweightsums[1][tmp] == 0);
    9957 }
    9958#endif
    9959
    9960 SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
    9961 SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
    9962
    9963 zeroitems[0] = -1; /* dummy element */
    9964 nextidxs[0] = -1;
    9965 nzeroitems = 1;
    9966 nliftcands[0] = 0;
    9967 nliftcands[1] = 0;
    9968
    9969 assert(conshdlrdata->bools1size > 0);
    9970 assert(conshdlrdata->bools2size > 0);
    9971
    9972 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
    9973 * than binary + integer variables existed at the presolving initialization method, but for example if you would
    9974 * transform all integers into their binary representation then it maybe happens
    9975 */
    9976 if( conshdlrdata->bools1size < nbinvars )
    9977 {
    9978 int oldsize = conshdlrdata->bools1size;
    9979
    9980 conshdlrdata->bools1size = nbinvars;
    9981 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
    9982 BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
    9983 }
    9984 if( conshdlrdata->bools2size < nbinvars )
    9985 {
    9986 int oldsize = conshdlrdata->bools2size;
    9987
    9988 conshdlrdata->bools2size = nbinvars;
    9989 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
    9990 BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
    9991 }
    9992
    9993 zeroiteminserted[0] = conshdlrdata->bools1;
    9994 zeroiteminserted[1] = conshdlrdata->bools2;
    9995
    9996 /* check for cleared arrays, all entries are zero */
    9997#ifndef NDEBUG
    9998 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
    9999 {
    10000 assert(zeroiteminserted[0][tmp] == 0);
    10001 assert(zeroiteminserted[1][tmp] == 0);
    10002 }
    10003#endif
    10004
    10005 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
    10006 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
    10007 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
    10008 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
    10009 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
    10010 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
    10011
    10012 tmp2 = 0;
    10013 tmp3 = 0;
    10014
    10015 memlimitreached = FALSE;
    10016 for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
    10017 {
    10018 SCIP_CLIQUE** cliques;
    10019 SCIP_VAR* var;
    10020 SCIP_Longint weight;
    10021 SCIP_Bool value;
    10022 int varprobindex;
    10023 int ncliques;
    10024 int j;
    10025
    10026 tmp = 0;
    10027
    10028 /* get corresponding active problem variable */
    10029 var = consdata->vars[i];
    10030 weight = consdata->weights[i];
    10031 value = TRUE;
    10032 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
    10033 varprobindex = SCIPvarGetProbindex(var);
    10034 assert(0 <= varprobindex && varprobindex < nbinvars);
    10035
    10036 /* update the zeroweightsum */
    10037 zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
    10038 tmpboolindices3[tmp3] = !value;
    10039 tmpindices3[tmp3] = varprobindex;
    10040 ++tmp3;
    10041
    10042 /* initialize the arrays of inserted zero items */
    10043 /* first add the implications (~x == 1 -> x == 0) */
    10044 {
    10045 SCIP_Bool implvalue;
    10046 int probindex;
    10047
    10048 probindex = SCIPvarGetProbindex(var);
    10049 assert(0 <= probindex && probindex < nbinvars);
    10050
    10051 implvalue = !value;
    10052
    10053 /* insert the item into the list of the implied variable/value */
    10054 assert( !zeroiteminserted[implvalue][probindex] );
    10055
    10056 if( firstidxs[implvalue][probindex] == 0 )
    10057 {
    10058 tmpboolindices2[tmp2] = implvalue;
    10059 tmpindices2[tmp2] = probindex;
    10060 ++tmp2;
    10061 }
    10062 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
    10063 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
    10064 &memlimitreached) );
    10065 zeroiteminserted[implvalue][probindex] = TRUE;
    10066 tmpboolindices[tmp] = implvalue;
    10067 tmpindices[tmp] = probindex;
    10068 ++tmp;
    10069 }
    10070
    10071 /* get the cliques where the knapsack item is member of with value 1 */
    10072 ncliques = SCIPvarGetNCliques(var, value);
    10073 cliques = SCIPvarGetCliques(var, value);
    10074 for( j = 0; j < ncliques && !memlimitreached; ++j )
    10075 {
    10076 SCIP_VAR** cliquevars;
    10077 SCIP_Bool* cliquevalues;
    10078 int ncliquevars;
    10079 int k;
    10080
    10081 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
    10082
    10083 /* discard big cliques */
    10084 if( ncliquevars > MAX_CLIQUELENGTH )
    10085 continue;
    10086
    10087 cliquevars = SCIPcliqueGetVars(cliques[j]);
    10088 cliquevalues = SCIPcliqueGetValues(cliques[j]);
    10089
    10090 for( k = ncliquevars - 1; k >= 0; --k )
    10091 {
    10092 SCIP_Bool implvalue;
    10093 int probindex;
    10094
    10095 if( var == cliquevars[k] )
    10096 continue;
    10097
    10098 probindex = SCIPvarGetProbindex(cliquevars[k]);
    10099 if( probindex == -1 )
    10100 continue;
    10101
    10102 assert(0 <= probindex && probindex < nbinvars);
    10103 implvalue = cliquevalues[k];
    10104
    10105 /* insert the item into the list of the clique variable/value */
    10106 if( !zeroiteminserted[implvalue][probindex] )
    10107 {
    10108 if( firstidxs[implvalue][probindex] == 0 )
    10109 {
    10110 tmpboolindices2[tmp2] = implvalue;
    10111 tmpindices2[tmp2] = probindex;
    10112 ++tmp2;
    10113 }
    10114
    10115 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
    10116 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
    10117 &memlimitreached) );
    10118 zeroiteminserted[implvalue][probindex] = TRUE;
    10119 tmpboolindices[tmp] = implvalue;
    10120 tmpindices[tmp] = probindex;
    10121 ++tmp;
    10122
    10123 if( memlimitreached )
    10124 break;
    10125 }
    10126 }
    10127 }
    10128 /* clear zeroiteminserted */
    10129 for( --tmp; tmp >= 0; --tmp)
    10130 zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
    10131 }
    10132 SCIPfreeBufferArray(scip, &tmpboolindices);
    10133
    10134 /* calculate the clique partition and the maximal sum of weights using the clique information */
    10135 assert(consdata->sorted);
    10136 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
    10137
    10138 assert(conshdlrdata->bools3size > 0);
    10139
    10140 /* next if condition should normally not be true, because it means that presolving has created more binary variables
    10141 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
    10142 * method, but for example if you would transform all integers into their binary representation then it maybe happens
    10143 */
    10144 if( conshdlrdata->bools3size < consdata->nvars )
    10145 {
    10146 int oldsize = conshdlrdata->bools3size;
    10147
    10148 conshdlrdata->bools3size = consdata->nvars;;
    10149 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
    10150 BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
    10151 }
    10152
    10153 cliqueused = conshdlrdata->bools3;
    10154
    10155 /* check for cleared array, all entries are zero */
    10156#ifndef NDEBUG
    10157 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
    10158 assert(cliqueused[tmp] == 0);
    10159#endif
    10160
    10161 maxcliqueweightsum = 0;
    10162 tmp = 0;
    10163
    10164 /* calculates maximal weight of cliques */
    10165 for( i = 0; i < consdata->nvars; ++i )
    10166 {
    10167 cliquenum = consdata->cliquepartition[i];
    10168 assert(0 <= cliquenum && cliquenum < consdata->nvars);
    10169
    10170 if( !cliqueused[cliquenum] )
    10171 {
    10172 maxcliqueweightsum += consdata->weights[i];
    10173 cliqueused[cliquenum] = TRUE;
    10174 tmpindices[tmp] = cliquenum;
    10175 ++tmp;
    10176 }
    10177 }
    10178 /* clear cliqueused */
    10179 for( --tmp; tmp >= 0; --tmp)
    10180 cliqueused[tmp] = FALSE;
    10181
    10182 assert(conshdlrdata->bools4size > 0);
    10183
    10184 /* next if condition should normally not be true, because it means that presolving has created more binary variables
    10185 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
    10186 * method, but for example if you would transform all integers into their binary representation then it maybe happens
    10187 */
    10188 if( conshdlrdata->bools4size < consdata->nvars )
    10189 {
    10190 int oldsize = conshdlrdata->bools4size;
    10191
    10192 conshdlrdata->bools4size = consdata->nvars;
    10193 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
    10194 BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
    10195 }
    10196
    10197 itemremoved = conshdlrdata->bools4;
    10198
    10199 /* check for cleared array, all entries are zero */
    10200#ifndef NDEBUG
    10201 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
    10202 assert(itemremoved[tmp] == 0);
    10203#endif
    10204
    10205 /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
    10206 * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
    10207 * included in subsequent cliqueweightsum calculations)
    10208 */
    10209 SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
    10210 SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
    10211 naddvars = 0;
    10212 addweightsum = 0;
    10213 for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
    10214 {
    10215 for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
    10216 {
    10217 SCIP_Longint cliqueweightsum;
    10218 int probindex;
    10219 int idx;
    10220 int j;
    10221
    10222 tmp = 0;
    10223
    10224 probindex = liftcands[val][i];
    10225 assert(0 <= probindex && probindex < nbinvars);
    10226
    10227 /* ignore empty zero lists and variables that cannot be lifted anyways */
    10228 if( firstidxs[val][probindex] == 0
    10229 || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
    10230 continue;
    10231
    10232 /* mark the items that are implied to zero by setting the current variable to the current value */
    10233 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
    10234 {
    10235 assert(0 < idx && idx < nzeroitems);
    10236 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
    10237 itemremoved[zeroitems[idx]] = TRUE;
    10238 }
    10239
    10240 /* calculate the residual cliqueweight sum */
    10241 cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
    10242 for( j = 0; j < consdata->nvars; ++j )
    10243 {
    10244 cliquenum = consdata->cliquepartition[j];
    10245 assert(0 <= cliquenum && cliquenum < consdata->nvars);
    10246 if( !itemremoved[j] )
    10247 {
    10248 if( !cliqueused[cliquenum] )
    10249 {
    10250 cliqueweightsum += consdata->weights[j];
    10251 cliqueused[cliquenum] = TRUE;
    10252 tmpindices[tmp] = cliquenum;
    10253 ++tmp;
    10254 }
    10255
    10256 if( cliqueweightsum >= consdata->capacity )
    10257 break;
    10258 }
    10259 }
    10260
    10261 /* check if the weight of the variable/value can be increased */
    10262 if( cliqueweightsum < consdata->capacity )
    10263 {
    10264 SCIP_VAR* var;
    10265 SCIP_Longint weight;
    10266
    10267 /* insert the variable (with value TRUE) in the list of additional items */
    10268 assert(naddvars < 2*nbinvars);
    10269 var = binvars[probindex];
    10270 if( val == FALSE )
    10271 {
    10272 SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
    10273 }
    10274 weight = consdata->capacity - cliqueweightsum;
    10275 addvars[naddvars] = var;
    10276 addweights[naddvars] = weight;
    10277 addweightsum += weight;
    10278 naddvars++;
    10279
    10280 SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
    10281 SCIPconsGetName(cons), weight, SCIPvarGetName(var));
    10282 }
    10283
    10284 /* clear itemremoved */
    10285 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
    10286 {
    10287 assert(0 < idx && idx < nzeroitems);
    10288 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
    10289 itemremoved[zeroitems[idx]] = FALSE;
    10290 }
    10291 /* clear cliqueused */
    10292 for( --tmp; tmp >= 0; --tmp)
    10293 cliqueused[tmpindices[tmp]] = FALSE;
    10294 }
    10295 }
    10296
    10297 /* clear part of zeroweightsums */
    10298 for( --tmp3; tmp3 >= 0; --tmp3)
    10299 zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
    10300
    10301 /* clear rest of zeroweightsums and firstidxs */
    10302 for( --tmp2; tmp2 >= 0; --tmp2)
    10303 {
    10304 zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
    10305 firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
    10306 }
    10307
    10308 /* add all additional item weights */
    10309 for( i = 0; i < naddvars; ++i )
    10310 {
    10311 SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
    10312 }
    10313 *nchgcoefs += naddvars;
    10314
    10315 if( naddvars > 0 )
    10316 {
    10317 /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
    10318 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    10319 }
    10320
    10321 /* free temporary memory */
    10322 SCIPfreeBufferArray(scip, &addweights);
    10323 SCIPfreeBufferArray(scip, &addvars);
    10324 SCIPfreeBufferArray(scip, &tmpindices);
    10325 SCIPfreeBufferArray(scip, &tmpindices2);
    10326 SCIPfreeBufferArray(scip, &tmpindices3);
    10327 SCIPfreeBufferArray(scip, &tmpboolindices2);
    10328 SCIPfreeBufferArray(scip, &tmpboolindices3);
    10329 SCIPfreeBufferArray(scip, &nextidxs);
    10330 SCIPfreeBufferArray(scip, &zeroitems);
    10331 SCIPfreeBufferArray(scip, &liftcands[1]);
    10332 SCIPfreeBufferArray(scip, &liftcands[0]);
    10333
    10334 return SCIP_OKAY;
    10335}
    10336
    10337/** tightens item weights and capacity in presolving:
    10338 * given a knapsack sum(wi*xi) <= capacity
    10339 * (1) let weightsum := sum(wi)
    10340 * if weightsum - wi < capacity:
    10341 * - not using item i would make the knapsack constraint redundant
    10342 * - wi and capacity can be changed to have the same redundancy effect and the same results for
    10343 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
    10344 * - change coefficients:
    10345 * wi' := weightsum - capacity
    10346 * capacity' := capacity - (wi - wi')
    10347 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
    10348 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
    10349 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
    10350 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
    10351 * can be multiple times the same weight, this can be improved
    10352 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
    10353 * weight, to capacity - lastmininmalweightsum, e.g. :
    10354 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
    10355 * -> minimal weightsums: 5, 5, 10, 10
    10356 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
    10357 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
    10358 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
    10359 * (3) let W(C) be the maximal weight of clique C,
    10360 * cliqueweightsum := sum(W(C))
    10361 * if cliqueweightsum - W(C) < capacity:
    10362 * - not using any item of C would make the knapsack constraint redundant
    10363 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
    10364 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
    10365 * - change coefficients:
    10366 * delta := capacity - (cliqueweightsum - W(C))
    10367 * wi' := max(wi - delta, 0)
    10368 * capacity' := capacity - delta
    10369 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
    10370 * introduce infeasible solutions.
    10371 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
    10372 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
    10373 * if cliqueweightsum(xi == v) < capacity:
    10374 * - fixing variable xi to v would make the knapsack constraint redundant
    10375 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
    10376 * redundancy effect:
    10377 * wi' := capacity - cliqueweightsum(xi == v)
    10378 * This rule can also be applied to binary variables not in the knapsack!
    10379 * (5) if min{w} + wi > capacity:
    10380 * - using item i would force to fix other items to zero
    10381 * - wi can be increased to the capacity
    10382 */
    10383static
    10385 SCIP* scip, /**< SCIP data structure */
    10386 SCIP_CONS* cons, /**< knapsack constraint */
    10387 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
    10388 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
    10389 int* nchgsides, /**< pointer to count number of side changes */
    10390 int* naddconss, /**< pointer to count number of added constraints */
    10391 int* ndelconss, /**< pointer to count number of deleted constraints */
    10392 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
    10393 )
    10394{
    10395 SCIP_CONSHDLRDATA* conshdlrdata;
    10396 SCIP_CONSDATA* consdata;
    10397 SCIP_Longint* weights;
    10398 SCIP_Longint sumcoef;
    10399 SCIP_Longint capacity;
    10400 SCIP_Longint newweight;
    10401 SCIP_Longint maxweight;
    10402 SCIP_Longint minweight;
    10403 SCIP_Bool sumcoefcase = FALSE;
    10404 int startpos;
    10405 int backpos;
    10406 int nvars;
    10407 int pos;
    10408 int k;
    10409 int i;
    10410
    10411 assert(nchgcoefs != NULL);
    10412 assert(nchgsides != NULL);
    10413 assert(!SCIPconsIsModifiable(cons));
    10414
    10415 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    10416 assert(conshdlrdata != NULL);
    10417
    10418 consdata = SCIPconsGetData(cons);
    10419 assert(consdata != NULL);
    10420 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
    10421 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
    10422 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
    10423 assert(consdata->nvars > 0);
    10424
    10425 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    10426 if( *cutoff )
    10427 return SCIP_OKAY;
    10428
    10429 /* apply rule (1) */
    10430 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    10431 {
    10432 do
    10433 {
    10434 assert(consdata->merged);
    10435
    10436 /* sort items, s.t. the heaviest one is in the first position */
    10437 sortItems(consdata);
    10438
    10439 for( i = 0; i < consdata->nvars; ++i )
    10440 {
    10441 SCIP_Longint weight;
    10442
    10443 weight = consdata->weights[i];
    10444 if( consdata->weightsum - weight < consdata->capacity )
    10445 {
    10446 newweight = consdata->weightsum - consdata->capacity;
    10447 consdataChgWeight(consdata, i, newweight);
    10448 consdata->capacity -= (weight - newweight);
    10449 (*nchgcoefs)++;
    10450 (*nchgsides)++;
    10451 assert(!consdata->sorted);
    10452 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",
    10453 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
    10454 consdata->capacity + (weight-newweight), consdata->capacity);
    10455 }
    10456 else
    10457 break;
    10458 }
    10459 }
    10460 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
    10461 }
    10462
    10463 /* check for redundancy */
    10464 if( consdata->weightsum <= consdata->capacity )
    10465 return SCIP_OKAY;
    10466
    10467 pos = 0;
    10468 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
    10469 ++pos;
    10470
    10471 sumcoef = 0;
    10472 weights = consdata->weights;
    10473 nvars = consdata->nvars;
    10474 capacity = consdata->capacity;
    10475
    10476 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
    10477 pos < nvars && weights[pos] + weights[pos + 1] > capacity )
    10478 {
    10479 /* further reductions using the next possible coefficient sum
    10480 *
    10481 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
    10482 */
    10483 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
    10484 for( k = 0; k < 4; ++k )
    10485 {
    10486 newweight = capacity - sumcoef;
    10487
    10488 /* determine next minimal coefficient sum */
    10489 switch( k )
    10490 {
    10491 case 0:
    10492 sumcoef = weights[nvars - 1];
    10493 backpos = nvars - 1;
    10494 break;
    10495 case 1:
    10496 sumcoef = weights[nvars - 2];
    10497 backpos = nvars - 2;
    10498 break;
    10499 case 2:
    10500 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
    10501 {
    10502 sumcoefcase = TRUE;
    10503 sumcoef = weights[nvars - 3];
    10504 backpos = nvars - 3;
    10505 }
    10506 else
    10507 {
    10508 sumcoefcase = FALSE;
    10509 sumcoef = weights[nvars - 1] + weights[nvars - 2];
    10510 backpos = nvars - 2;
    10511 }
    10512 break;
    10513 default:
    10514 assert(k == 3);
    10515 if( sumcoefcase )
    10516 {
    10517 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
    10518 {
    10519 sumcoef = weights[nvars - 4];
    10520 backpos = nvars - 4;
    10521 }
    10522 else
    10523 {
    10524 sumcoef = weights[nvars - 1] + weights[nvars - 2];
    10525 backpos = nvars - 2;
    10526 }
    10527 }
    10528 else
    10529 {
    10530 sumcoef = weights[nvars - 3];
    10531 backpos = nvars - 3;
    10532 }
    10533 break;
    10534 }
    10535
    10536 if( backpos <= pos )
    10537 break;
    10538
    10539 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
    10540 maxweight = weights[pos];
    10541 startpos = pos;
    10542 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
    10543 {
    10544 assert(newweight > weights[pos]);
    10545
    10546 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10547 SCIPconsGetName(cons), maxweight, newweight);
    10548
    10549 consdataChgWeight(consdata, pos, newweight);
    10550
    10551 ++pos;
    10552 assert(pos < nvars);
    10553
    10554 maxweight = weights[pos];
    10555
    10556 if( backpos <= pos )
    10557 break;
    10558 }
    10559 (*nchgcoefs) += (pos - startpos);
    10560
    10561 /* skip unchangable weights */
    10562 while( pos < nvars && weights[pos] + sumcoef == capacity )
    10563 ++pos;
    10564
    10565 /* check special case were there is only one weight left to tighten
    10566 *
    10567 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
    10568 *
    10569 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
    10570 *
    10571 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
    10572 */
    10573 if( pos + 1 == backpos && weights[pos] > sumcoef &&
    10574 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
    10575 {
    10576 newweight = capacity - sumcoef;
    10577 assert(newweight > weights[pos]);
    10578
    10579 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10580 SCIPconsGetName(cons), maxweight, newweight);
    10581
    10582 consdataChgWeight(consdata, pos, newweight);
    10583
    10584 break;
    10585 }
    10586
    10587 if( backpos <= pos )
    10588 break;
    10589 }
    10590 }
    10591
    10592 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
    10593 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    10594 {
    10595 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0
    10596 && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 && pos > 0
    10597 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity
    10598 && consdata->weights[pos - 1] == consdata->capacity
    10599 && ( pos == consdata->nvars || consdata->weights[pos] == 1 ) )
    10600 {
    10601 SCIP_VAR** clqvars;
    10602 SCIP_CONS* cliquecons;
    10603 char name[SCIP_MAXSTRLEN];
    10604 int* clqpart;
    10605 int nclqvars;
    10606 int nclq;
    10607 int len;
    10608 int c;
    10609 int w;
    10610
    10611 assert(!SCIPconsIsDeleted(cons));
    10612
    10613 if( pos == consdata->nvars )
    10614 {
    10615 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
    10616
    10617 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
    10621 SCIPconsIsStickingAtNode(cons)) );
    10622
    10623 /* add the upgraded constraint to the problem */
    10624 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    10625 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    10626 ++(*naddconss);
    10627
    10628 /* delete old constraint */
    10629 SCIP_CALL( SCIPdelCons(scip, cons) );
    10630 ++(*ndelconss);
    10631
    10632 return SCIP_OKAY;
    10633 }
    10634
    10635 len = consdata->nvars - pos;
    10636
    10637 /* allocate temporary memory */
    10638 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
    10639
    10640 /* calculate clique partition */
    10641 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
    10642 assert(nclq <= len);
    10643
    10644#ifndef NDEBUG
    10645 /* clique numbers must be at least as high as the index */
    10646 for( w = 0; w < nclq; ++w )
    10647 assert(clqpart[w] <= w);
    10648#endif
    10649
    10650 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
    10651
    10652 /* allocate temporary memory */
    10653 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
    10654
    10655 /* copy corresponding variables with big coefficients */
    10656 for( w = pos - 1; w >= 0; --w )
    10657 clqvars[w] = consdata->vars[w];
    10658
    10659 /* create for each clique a set-packing constraint */
    10660 for( c = 0; c < nclq; ++c )
    10661 {
    10662 nclqvars = pos;
    10663
    10664 for( w = c; w < len; ++w )
    10665 {
    10666 if( clqpart[w] == c )
    10667 {
    10668 assert(nclqvars < pos + len - nclq + 1);
    10669 clqvars[nclqvars] = consdata->vars[w + pos];
    10670 ++nclqvars;
    10671 }
    10672 }
    10673
    10674 assert(nclqvars > 1);
    10675
    10676 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
    10677 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
    10681 SCIPconsIsStickingAtNode(cons)) );
    10682
    10683 /* add the special constraint to the problem */
    10684 SCIPdebugMsg(scip, " -> adding clique constraint: ");
    10685 SCIPdebugPrintCons(scip, cliquecons, NULL);
    10686 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    10687 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    10688 ++(*naddconss);
    10689 }
    10690
    10691 /* delete old constraint */
    10692 SCIP_CALL( SCIPdelCons(scip, cons) );
    10693 ++(*ndelconss);
    10694
    10695 SCIPfreeBufferArray(scip, &clqvars);
    10696 SCIPfreeBufferArray(scip, &clqpart);
    10697
    10698 return SCIP_OKAY;
    10699 }
    10700 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
    10701 {
    10702 SCIP_Longint* maxcliqueweights;
    10703 SCIP_Longint* newweightvals;
    10704 int* newweightidxs;
    10705 SCIP_Longint cliqueweightsum;
    10706
    10707 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
    10708 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
    10709 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
    10710
    10711 /* repeat as long as changes have been applied */
    10712 do
    10713 {
    10714 int ncliques;
    10715 int cliquenum;
    10716 SCIP_Bool zeroweights;
    10717
    10718 assert(consdata->merged);
    10719
    10720 /* sort items, s.t. the heaviest one is in the first position */
    10721 sortItems(consdata);
    10722
    10723 /* calculate a clique partition */
    10724 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
    10725
    10726 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
    10727 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
    10728 break;
    10729
    10730 /* calculate the maximal weight of the cliques and store the clique type */
    10731 cliqueweightsum = 0;
    10732 ncliques = 0;
    10733
    10734 for( i = 0; i < consdata->nvars; ++i )
    10735 {
    10736 SCIP_Longint weight;
    10737
    10738 cliquenum = consdata->cliquepartition[i];
    10739 assert(0 <= cliquenum && cliquenum <= ncliques);
    10740
    10741 weight = consdata->weights[i];
    10742 assert(weight > 0);
    10743
    10744 if( cliquenum == ncliques )
    10745 {
    10746 maxcliqueweights[ncliques] = weight;
    10747 cliqueweightsum += weight;
    10748 ++ncliques;
    10749 }
    10750
    10751 assert(maxcliqueweights[cliquenum] >= weight);
    10752 }
    10753
    10754 /* apply rule on every clique */
    10755 zeroweights = FALSE;
    10756 for( i = 0; i < ncliques; ++i )
    10757 {
    10758 SCIP_Longint delta;
    10759
    10760 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
    10761 if( delta > 0 )
    10762 {
    10763 SCIP_Longint newcapacity;
    10764#ifndef NDEBUG
    10765 SCIP_Longint newmincliqueweight;
    10766#endif
    10767 SCIP_Longint newminweightsuminclique;
    10768 SCIP_Bool forceclique;
    10769 int nnewweights;
    10770 int j;
    10771
    10772 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",
    10773 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
    10774 newcapacity = consdata->capacity - delta;
    10775 forceclique = FALSE;
    10776 nnewweights = 0;
    10777#ifndef NDEBUG
    10778 newmincliqueweight = newcapacity + 1;
    10779 for( j = 0; j < i; ++j )
    10780 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
    10781#endif
    10782 for( j = i; j < consdata->nvars; ++j )
    10783 {
    10784 if( consdata->cliquepartition[j] == i )
    10785 {
    10786 newweight = consdata->weights[j] - delta;
    10787 newweight = MAX(newweight, 0);
    10788
    10789 /* cache the new weight */
    10790 assert(nnewweights < consdata->nvars);
    10791 newweightvals[nnewweights] = newweight;
    10792 newweightidxs[nnewweights] = j;
    10793 nnewweights++;
    10794
    10795#ifndef NDEBUG
    10796 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
    10797 newmincliqueweight = newweight;
    10798#endif
    10799 }
    10800 }
    10801
    10802 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
    10803 if( nnewweights > 1 )
    10804 {
    10805#ifndef NDEBUG
    10806 j = newweightidxs[nnewweights - 2];
    10807 assert(0 <= j && j < consdata->nvars);
    10808 assert(consdata->cliquepartition[j] == i);
    10809 j = newweightidxs[nnewweights - 1];
    10810 assert(0 <= j && j < consdata->nvars);
    10811 assert(consdata->cliquepartition[j] == i);
    10812#endif
    10813
    10814 newminweightsuminclique = newweightvals[nnewweights - 2];
    10815 newminweightsuminclique += newweightvals[nnewweights - 1];
    10816
    10817 /* check if these new two minimal weights both fit into the knapsack;
    10818 * if this is true, we have to add a clique constraint in order to enforce the clique
    10819 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
    10820 * reduction might be infeasible, i.e., allows additional solutions)
    10821 */
    10822 if( newminweightsuminclique <= newcapacity )
    10823 forceclique = TRUE;
    10824 }
    10825
    10826 /* check if we really want to apply the change */
    10827 if( conshdlrdata->disaggregation || !forceclique )
    10828 {
    10829 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
    10830 consdata->capacity, newcapacity, forceclique);
    10831 consdata->capacity = newcapacity;
    10832 (*nchgsides)++;
    10833
    10834 for( k = 0; k < nnewweights; ++k )
    10835 {
    10836 j = newweightidxs[k];
    10837 assert(0 <= j && j < consdata->nvars);
    10838 assert(consdata->cliquepartition[j] == i);
    10839
    10840 /* apply the weight change */
    10841 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10842 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
    10843 consdataChgWeight(consdata, j, newweightvals[k]);
    10844 (*nchgcoefs)++;
    10845 assert(!consdata->sorted);
    10846 zeroweights = zeroweights || (newweightvals[k] == 0);
    10847 }
    10848 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
    10849 * we have to make sure, the clique is enforced - the clique might have been constructed partially from
    10850 * this constraint, and by reducing the weights, this clique information is not contained anymore in the
    10851 * knapsack constraint
    10852 */
    10853 if( forceclique )
    10854 {
    10855 SCIP_CONS* cliquecons;
    10856 char name[SCIP_MAXSTRLEN];
    10857 SCIP_VAR** cliquevars;
    10858
    10859 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
    10860 for( k = 0; k < nnewweights; ++k )
    10861 cliquevars[k] = consdata->vars[newweightidxs[k]];
    10862
    10863 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
    10864 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
    10868 SCIPconsIsStickingAtNode(cons)) );
    10869
    10870 /* add the special constraint to the problem */
    10871 SCIPdebugMsg(scip, " -> adding clique constraint: ");
    10872 SCIPdebugPrintCons(scip, cliquecons, NULL);
    10873 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
    10874 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
    10875 ++(*naddconss);
    10876
    10877 /* free clique array */
    10878 SCIPfreeBufferArray(scip, &cliquevars);
    10879 }
    10880 }
    10881 }
    10882 }
    10883 if( zeroweights )
    10884 {
    10886 }
    10887 }
    10888 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
    10889
    10890 /* free temporary memory */
    10891 SCIPfreeBufferArray(scip, &newweightidxs);
    10892 SCIPfreeBufferArray(scip, &newweightvals);
    10893 SCIPfreeBufferArray(scip, &maxcliqueweights);
    10894
    10895 /* check for redundancy */
    10896 if( consdata->weightsum <= consdata->capacity )
    10897 return SCIP_OKAY;
    10898 }
    10899 }
    10900
    10901 /* apply rule (3) */
    10902 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    10903 {
    10904 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
    10905 }
    10906
    10907 /* check for redundancy */
    10908 if( consdata->weightsum <= consdata->capacity )
    10909 return SCIP_OKAY;
    10910
    10911 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    10912 {
    10913 /* apply rule (4) (all but smallest weight) */
    10914 assert(consdata->merged);
    10915 sortItems(consdata);
    10916 minweight = consdata->weights[consdata->nvars-1];
    10917 for( i = 0; i < consdata->nvars-1; ++i )
    10918 {
    10919 SCIP_Longint weight;
    10920
    10921 weight = consdata->weights[i];
    10922 assert(weight >= minweight);
    10923 if( minweight + weight > consdata->capacity )
    10924 {
    10925 if( weight < consdata->capacity )
    10926 {
    10927 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10928 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
    10929 assert(consdata->sorted);
    10930 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
    10931 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
    10932 consdata->sorted = TRUE;
    10933 (*nchgcoefs)++;
    10934 }
    10935 }
    10936 else
    10937 break;
    10938 }
    10939
    10940 /* apply rule (5) (smallest weight) */
    10941 if( consdata->nvars >= 2 )
    10942 {
    10943 SCIP_Longint weight;
    10944
    10945 minweight = consdata->weights[consdata->nvars-2];
    10946 weight = consdata->weights[consdata->nvars-1];
    10947 assert(minweight >= weight);
    10948 if( minweight + weight > consdata->capacity && weight < consdata->capacity )
    10949 {
    10950 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
    10951 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
    10952 assert(consdata->sorted);
    10953 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
    10954 assert(minweight >= consdata->weights[consdata->nvars-1]);
    10955 consdata->sorted = TRUE;
    10956 (*nchgcoefs)++;
    10957 }
    10958 }
    10959 }
    10960
    10961 return SCIP_OKAY;
    10962}
    10963
    10964
    10965#ifdef SCIP_DEBUG
    10966static
    10967void printClique(
    10968 SCIP_VAR** cliquevars,
    10969 int ncliquevars
    10970 )
    10971{
    10972 int b;
    10973 SCIPdebugMessage("adding new Clique: ");
    10974 for( b = 0; b < ncliquevars; ++b )
    10975 SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
    10976 SCIPdebugPrintf("\n");
    10977}
    10978#endif
    10979
    10980/** adds negated cliques of the knapsack constraint to the global clique table */
    10981static
    10983 SCIP*const scip, /**< SCIP data structure */
    10984 SCIP_CONS*const cons, /**< knapsack constraint */
    10985 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
    10986 int*const nbdchgs /**< pointer to count the number of performed bound changes */
    10987 )
    10988{
    10989 SCIP_CONSDATA* consdata;
    10990 SCIP_CONSHDLRDATA* conshdlrdata;
    10991 SCIP_VAR** poscliquevars;
    10992 SCIP_VAR** cliquevars;
    10993 SCIP_Longint* maxweights;
    10994 SCIP_Longint* gainweights;
    10995 int* gaincliquepartition;
    10996 SCIP_Bool* cliqueused;
    10997 SCIP_Longint minactduetonegcliques;
    10998 SCIP_Longint freecapacity;
    10999 SCIP_Longint lastweight;
    11000 SCIP_Longint beforelastweight;
    11001 int nposcliquevars;
    11002 int ncliquevars;
    11003 int nvars;
    11004 int nnegcliques;
    11005 int lastcliqueused;
    11006 int thisnbdchgs;
    11007 int v;
    11008 int w;
    11009
    11010 assert(scip != NULL);
    11011 assert(cons != NULL);
    11012 assert(cutoff != NULL);
    11013 assert(nbdchgs != NULL);
    11014
    11015 *cutoff = FALSE;
    11016
    11017 consdata = SCIPconsGetData(cons);
    11018 assert(consdata != NULL);
    11019
    11020 nvars = consdata->nvars;
    11021
    11022 /* check whether the cliques have already been added */
    11023 if( consdata->cliquesadded || nvars == 0 )
    11024 return SCIP_OKAY;
    11025
    11026 /* make sure, the items are merged */
    11027 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    11028 if( *cutoff )
    11029 return SCIP_OKAY;
    11030
    11031 /* make sure, items are sorted by non-increasing weight */
    11032 sortItems(consdata);
    11033
    11034 assert(consdata->merged);
    11035
    11036 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    11037 assert(conshdlrdata != NULL);
    11038
    11039 /* calculate a clique partition */
    11040 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
    11041 nnegcliques = consdata->nnegcliques;
    11042
    11043 /* if we have no negated cliques, stop */
    11044 if( nnegcliques == nvars )
    11045 return SCIP_OKAY;
    11046
    11047 /* get temporary memory */
    11048 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
    11049 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
    11050 SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
    11051 SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
    11052 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
    11053 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
    11054
    11055 nnegcliques = 0;
    11056 minactduetonegcliques = 0;
    11057
    11058 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
    11059 for( v = 0; v < nvars; ++v )
    11060 {
    11061 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
    11062 assert(consdata->weights[v] > 0);
    11063
    11064 if( consdata->negcliquepartition[v] == nnegcliques )
    11065 {
    11066 nnegcliques++;
    11067 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
    11068 }
    11069 else
    11070 minactduetonegcliques += consdata->weights[v];
    11071 }
    11072
    11073 nposcliquevars = 0;
    11074
    11075 /* add cliques, using negated cliques information */
    11076 if( minactduetonegcliques > 0 )
    11077 {
    11078 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
    11079 freecapacity = consdata->capacity - minactduetonegcliques;
    11080
    11082 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",
    11083 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
    11084
    11085 /* calculate possible gain by switching chosen items in negated cliques */
    11086 for( v = 0; v < nvars; ++v )
    11087 {
    11088 if( !cliqueused[consdata->negcliquepartition[v]] )
    11089 {
    11090 cliqueused[consdata->negcliquepartition[v]] = TRUE;
    11091 for( w = v + 1; w < nvars; ++w )
    11092 {
    11093 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
    11094 * weight[w] (which are both in a negated clique) */
    11095 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
    11096 && consdata->weights[v] > consdata->weights[w] )
    11097 {
    11098 poscliquevars[nposcliquevars] = consdata->vars[w];
    11099 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
    11100 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
    11101 ++nposcliquevars;
    11102 }
    11103 }
    11104 }
    11105 }
    11106
    11107 /* try to create negated cliques */
    11108 if( nposcliquevars > 0 )
    11109 {
    11110 /* sort possible gain per substitution of the clique members */
    11111 SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
    11112
    11113 for( v = 0; v < nposcliquevars; ++v )
    11114 {
    11115 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
    11116 ncliquevars = 1;
    11117 lastweight = gainweights[v];
    11118 beforelastweight = -1;
    11119 lastcliqueused = gaincliquepartition[v];
    11120 /* clear cliqueused to get an unused array */
    11121 BMSclearMemoryArray(cliqueused, nnegcliques);
    11122 cliqueused[gaincliquepartition[v]] = TRUE;
    11123
    11124 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
    11125 * in the same negated clique and by taking two of them would exceed the free capacity */
    11126 for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
    11127 {
    11128 beforelastweight = lastweight;
    11129 lastweight = gainweights[w];
    11130 lastcliqueused = gaincliquepartition[w];
    11131 cliqueused[gaincliquepartition[w]] = TRUE;
    11132 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
    11133 ++ncliquevars;
    11134 }
    11135
    11136 if( ncliquevars > 1 )
    11137 {
    11138 SCIPdebug( printClique(cliquevars, ncliquevars) );
    11139 assert(beforelastweight > 0);
    11140 /* add the clique to the clique table */
    11141 /* this really happens, e.g., on enigma.mps from the short test set */
    11142 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
    11143 if( *cutoff )
    11144 goto TERMINATE;
    11145 *nbdchgs += thisnbdchgs;
    11146
    11147 /* reset last used clique to get slightly different cliques */
    11148 cliqueused[lastcliqueused] = FALSE;
    11149
    11150 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
    11151 for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
    11152 {
    11153 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
    11154 SCIPdebug( printClique(cliquevars, ncliquevars) );
    11155 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
    11156 if( *cutoff )
    11157 goto TERMINATE;
    11158 *nbdchgs += thisnbdchgs;
    11159 }
    11160 }
    11161 }
    11162 }
    11163 }
    11164
    11165 TERMINATE:
    11166 /* free temporary memory */
    11167 SCIPfreeBufferArray(scip, &cliqueused);
    11168 SCIPfreeBufferArray(scip, &maxweights);
    11169 SCIPfreeBufferArray(scip, &gaincliquepartition);
    11170 SCIPfreeBufferArray(scip, &gainweights);
    11171 SCIPfreeBufferArray(scip, &cliquevars);
    11172 SCIPfreeBufferArray(scip, &poscliquevars);
    11173
    11174 return SCIP_OKAY;
    11175}
    11176
    11177/** greedy clique detection by considering weights and capacity
    11178 *
    11179 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
    11180 * 1) neighboring items which exceed the capacity together => one clique
    11181 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
    11182 */
    11183static
    11185 SCIP*const scip, /**< SCIP data structure */
    11186 SCIP_VAR** items, /**< array of variable items */
    11187 SCIP_Longint* weights, /**< weights of the items */
    11188 int nitems, /**< the number of items */
    11189 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
    11190 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
    11191 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
    11192 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
    11193 int*const nbdchgs /**< pointer to count the number of performed bound changes */
    11194 )
    11195{
    11196 SCIP_Longint lastweight;
    11197 int ncliquevars;
    11198 int i;
    11199 int thisnbdchgs;
    11200
    11201 if( nitems <= 1 )
    11202 return SCIP_OKAY;
    11203
    11204 /* sort possible gain per substitution of the clique members */
    11205 if( ! sorteditems )
    11206 SCIPsortDownLongPtr(weights,(void**) items, nitems);
    11207
    11208 ncliquevars = 1;
    11209 lastweight = weights[0];
    11210
    11211 /* taking these two weights together violates the knapsack => include into clique */
    11212 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
    11213 {
    11214 lastweight = weights[i];
    11215 ++ncliquevars;
    11216 }
    11217
    11218 if( ncliquevars > 1 )
    11219 {
    11220 SCIP_Longint compareweight;
    11221 SCIP_VAR** cliquevars;
    11222 int compareweightidx;
    11223 int minclqsize;
    11224 int nnzadded;
    11225
    11226 /* add the clique to the clique table */
    11227 SCIPdebug( printClique(items, ncliquevars) );
    11228 SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
    11229
    11230 if( *cutoff )
    11231 return SCIP_OKAY;
    11232
    11233 *nbdchgs += thisnbdchgs;
    11234 nnzadded = ncliquevars;
    11235
    11236 /* 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)*/
    11237 if( ncliquevars == nitems )
    11238 return SCIP_OKAY;
    11239
    11240 /* copy items in order into buffer array and deduce more cliques */
    11241 SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
    11242
    11243 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
    11244 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
    11245 compareweightidx = ncliquevars - 2;
    11246 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
    11247
    11248 /* determine minimum clique size for the following loop */
    11249 minclqsize = (int)(cliqueextractfactor * ncliquevars);
    11250 minclqsize = MAX(minclqsize, 2);
    11251
    11252 /* loop over the remaining variables and the larger items of the first clique until we
    11253 * find another clique or reach the size limit */
    11254 while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
    11255 && ncliquevars >= minclqsize /* stop at a given minimum clique size */
    11256 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
    11257 )
    11258 {
    11259 compareweight = weights[compareweightidx];
    11260 assert(compareweight > 0);
    11261
    11262 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
    11263 if( compareweight + weights[i] > capacity )
    11264 {
    11265 assert(compareweightidx == ncliquevars -2);
    11266 cliquevars[ncliquevars - 1] = items[i];
    11267 SCIPdebug( printClique(cliquevars, ncliquevars) );
    11268 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
    11269
    11270 nnzadded += ncliquevars;
    11271
    11272 /* stop when there is a cutoff */
    11273 if( ! (*cutoff) )
    11274 *nbdchgs += thisnbdchgs;
    11275
    11276 /* go to next smaller item */
    11277 ++i;
    11278 }
    11279 else
    11280 {
    11281 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
    11282 compareweightidx--;
    11283 ncliquevars --;
    11284 }
    11285 }
    11286
    11287 SCIPfreeBufferArray(scip, &cliquevars);
    11288 }
    11289
    11290 return SCIP_OKAY;
    11291}
    11292
    11293/** adds cliques of the knapsack constraint to the global clique table */
    11294static
    11296 SCIP*const scip, /**< SCIP data structure */
    11297 SCIP_CONS*const cons, /**< knapsack constraint */
    11298 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
    11299 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
    11300 int*const nbdchgs /**< pointer to count the number of performed bound changes */
    11301 )
    11302{
    11303 SCIP_CONSDATA* consdata;
    11304 SCIP_CONSHDLRDATA* conshdlrdata;
    11305 int i;
    11306 SCIP_Longint minactduetonegcliques;
    11307 SCIP_Longint freecapacity;
    11308 int nnegcliques;
    11309 int cliquenum;
    11310 SCIP_VAR** poscliquevars;
    11311 SCIP_Longint* gainweights;
    11312 int nposcliquevars;
    11313 SCIP_Longint* secondmaxweights;
    11314 int nvars;
    11315
    11316 assert(scip != NULL);
    11317 assert(cons != NULL);
    11318 assert(cutoff != NULL);
    11319 assert(nbdchgs != NULL);
    11320
    11321 *cutoff = FALSE;
    11322
    11323 consdata = SCIPconsGetData(cons);
    11324 assert(consdata != NULL);
    11325
    11326 nvars = consdata->nvars;
    11327
    11328 /* check whether the cliques have already been added */
    11329 if( consdata->cliquesadded || nvars == 0 )
    11330 return SCIP_OKAY;
    11331
    11332 /* make sure, the items are merged */
    11333 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
    11334 if( *cutoff )
    11335 return SCIP_OKAY;
    11336
    11337 /* make sure, the items are sorted by non-increasing weight */
    11338 sortItems(consdata);
    11339
    11340 assert(consdata->merged);
    11341
    11342 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    11343 assert(conshdlrdata != NULL);
    11344
    11345 /* calculate a clique partition */
    11346 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
    11347 nnegcliques = consdata->nnegcliques;
    11348 assert(nnegcliques <= nvars);
    11349
    11350 /* get temporary memory */
    11351 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
    11352 SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
    11353 BMSclearMemoryArray(gainweights, nvars);
    11354 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
    11355 BMSclearMemoryArray(secondmaxweights, nnegcliques);
    11356
    11357 minactduetonegcliques = 0;
    11358
    11359 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
    11360 if( nnegcliques < nvars )
    11361 {
    11362 nnegcliques = 0;
    11363
    11364 for( i = 0; i < nvars; ++i )
    11365 {
    11366 SCIP_Longint weight;
    11367
    11368 cliquenum = consdata->negcliquepartition[i];
    11369 assert(0 <= cliquenum && cliquenum <= nnegcliques);
    11370
    11371 weight = consdata->weights[i];
    11372 assert(weight > 0);
    11373
    11374 if( cliquenum == nnegcliques )
    11375 nnegcliques++;
    11376 else
    11377 {
    11378 minactduetonegcliques += weight;
    11379 if( secondmaxweights[cliquenum] == 0 )
    11380 secondmaxweights[cliquenum] = weight;
    11381 }
    11382 }
    11383 }
    11384
    11385 /* add cliques, using negated cliques information */
    11386 if( minactduetonegcliques > 0 )
    11387 {
    11388 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
    11389 freecapacity = consdata->capacity - minactduetonegcliques;
    11390
    11392 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",
    11393 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
    11394
    11395 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
    11396 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
    11397
    11398 if( *cutoff )
    11399 goto TERMINATE;
    11400
    11401 nposcliquevars = 0;
    11402
    11403 for( i = nvars - 1; i >= 0; --i )
    11404 {
    11405 /* if we would take the biggest weight instead of the second biggest */
    11406 cliquenum = consdata->negcliquepartition[i];
    11407 if( consdata->weights[i] > secondmaxweights[cliquenum] )
    11408 {
    11409 poscliquevars[nposcliquevars] = consdata->vars[i];
    11410 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
    11411 ++nposcliquevars;
    11412 }
    11413 }
    11414
    11415 /* use the gain weights and free capacity to derive greedily cliques */
    11416 if( nposcliquevars > 1 )
    11417 {
    11418 SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
    11419
    11420 if( *cutoff )
    11421 goto TERMINATE;
    11422 }
    11423 }
    11424
    11425 /* build cliques by using the items with the maximal weights */
    11426 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
    11427
    11428 TERMINATE:
    11429 /* free temporary memory and mark the constraint */
    11430 SCIPfreeBufferArray(scip, &secondmaxweights);
    11431 SCIPfreeBufferArray(scip, &gainweights);
    11432 SCIPfreeBufferArray(scip, &poscliquevars);
    11433 consdata->cliquesadded = TRUE;
    11434
    11435 return SCIP_OKAY;
    11436}
    11437
    11438
    11439/** gets the key of the given element */
    11440static
    11441SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
    11442{ /*lint --e{715}*/
    11443 /* the key is the element itself */
    11444 return elem;
    11445}
    11446
    11447/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
    11448 * same coefficients
    11449 */
    11450static
    11451SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
    11452{
    11453#ifndef NDEBUG
    11454 SCIP* scip;
    11455#endif
    11456 SCIP_CONSDATA* consdata1;
    11457 SCIP_CONSDATA* consdata2;
    11458 int i;
    11459
    11460 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
    11461 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
    11462 assert(consdata1->sorted);
    11463 assert(consdata2->sorted);
    11464#ifndef NDEBUG
    11465 scip = (SCIP*)userptr;
    11466 assert(scip != NULL);
    11467#endif
    11468
    11469 /* checks trivial case */
    11470 if( consdata1->nvars != consdata2->nvars )
    11471 return FALSE;
    11472
    11473 for( i = consdata1->nvars - 1; i >= 0; --i )
    11474 {
    11475 /* tests if variables are equal */
    11476 if( consdata1->vars[i] != consdata2->vars[i] )
    11477 {
    11478 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
    11479 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
    11480 return FALSE;
    11481 }
    11482 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
    11483
    11484 /* tests if weights are equal too */
    11485 if( consdata1->weights[i] != consdata2->weights[i] )
    11486 return FALSE;
    11487 }
    11488
    11489 return TRUE;
    11490}
    11491
    11492/** returns the hash value of the key */
    11493static
    11494SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
    11495{
    11496#ifndef NDEBUG
    11497 SCIP* scip;
    11498#endif
    11499 SCIP_CONSDATA* consdata;
    11500 uint64_t firstweight;
    11501 int minidx;
    11502 int mididx;
    11503 int maxidx;
    11504
    11505 consdata = SCIPconsGetData((SCIP_CONS*)key);
    11506 assert(consdata != NULL);
    11507 assert(consdata->nvars > 0);
    11508
    11509#ifndef NDEBUG
    11510 scip = (SCIP*)userptr;
    11511 assert(scip != NULL);
    11512#endif
    11513
    11514 /* sorts the constraints */
    11515 sortItems(consdata);
    11516
    11517 minidx = SCIPvarGetIndex(consdata->vars[0]);
    11518 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
    11519 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
    11520 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
    11521
    11522 /* hash value depends on vectors of variable indices */
    11523 firstweight = (uint64_t)consdata->weights[0];
    11524 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
    11525}
    11526
    11527/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
    11528 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
    11529 */
    11530static
    11532 SCIP* scip, /**< SCIP data structure */
    11533 BMS_BLKMEM* blkmem, /**< block memory */
    11534 SCIP_CONS** conss, /**< constraint set */
    11535 int nconss, /**< number of constraints in constraint set */
    11536 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
    11537 int* ndelconss /**< pointer to count number of deleted constraints */
    11538 )
    11539{
    11540 SCIP_HASHTABLE* hashtable;
    11541 int hashtablesize;
    11542 int c;
    11543
    11544 assert(scip != NULL);
    11545 assert(blkmem != NULL);
    11546 assert(conss != NULL);
    11547 assert(ndelconss != NULL);
    11548
    11549 /* create a hash table for the constraint set */
    11550 hashtablesize = nconss;
    11551 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
    11552 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
    11553 hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
    11554
    11555 /* check all constraints in the given set for redundancy */
    11556 for( c = nconss - 1; c >= 0; --c )
    11557 {
    11558 SCIP_CONS* cons0;
    11559 SCIP_CONS* cons1;
    11560 SCIP_CONSDATA* consdata0;
    11561
    11562 cons0 = conss[c];
    11563
    11564 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
    11565 continue;
    11566
    11567 consdata0 = SCIPconsGetData(cons0);
    11568 assert(consdata0 != NULL);
    11569 if( consdata0->nvars == 0 )
    11570 {
    11571 if( consdata0->capacity < 0 )
    11572 {
    11573 *cutoff = TRUE;
    11574 goto TERMINATE;
    11575 }
    11576 else
    11577 {
    11578 SCIP_CALL( SCIPdelCons(scip, cons0) );
    11579 ++(*ndelconss);
    11580 continue;
    11581 }
    11582 }
    11583
    11584 /* get constraint from current hash table with same variables and same weights as cons0 */
    11585 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
    11586
    11587 if( cons1 != NULL )
    11588 {
    11589 SCIP_CONS* consstay;
    11590 SCIP_CONS* consdel;
    11591 SCIP_CONSDATA* consdata1;
    11592
    11593 assert(SCIPconsIsActive(cons1));
    11594 assert(!SCIPconsIsModifiable(cons1));
    11595
    11596 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
    11597 * delete old constraints afterwards
    11598 */
    11599 consdata1 = SCIPconsGetData(cons1);
    11600
    11601 assert(consdata1 != NULL);
    11602 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
    11603
    11604 assert(consdata0->sorted && consdata1->sorted);
    11605 assert(consdata0->vars[0] == consdata1->vars[0]);
    11606 assert(consdata0->weights[0] == consdata1->weights[0]);
    11607
    11608 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
    11609 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
    11610
    11611 /* check which constraint has to stay; */
    11612 if( consdata0->capacity < consdata1->capacity )
    11613 {
    11614 consstay = cons0;
    11615 consdel = cons1;
    11616
    11617 /* exchange consdel with consstay in hashtable */
    11618 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
    11619 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
    11620 }
    11621 else
    11622 {
    11623 consstay = cons1;
    11624 consdel = cons0;
    11625 }
    11626
    11627 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
    11628 SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
    11629
    11630 /* delete consdel */
    11631 SCIP_CALL( SCIPdelCons(scip, consdel) );
    11632 ++(*ndelconss);
    11633
    11634 assert(SCIPconsIsActive(consstay));
    11635 }
    11636 else
    11637 {
    11638 /* no such constraint in current hash table: insert cons0 into hash table */
    11639 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
    11640 }
    11641 }
    11642
    11643 TERMINATE:
    11644 /* free hash table */
    11645 SCIPhashtableFree(&hashtable);
    11646
    11647 return SCIP_OKAY;
    11648}
    11649
    11650
    11651/** compares constraint with all prior constraints for possible redundancy or aggregation,
    11652 * and removes or changes constraint accordingly
    11653 */
    11654static
    11656 SCIP* scip, /**< SCIP data structure */
    11657 SCIP_CONS** conss, /**< constraint set */
    11658 int firstchange, /**< first constraint that changed since last pair preprocessing round */
    11659 int chkind, /**< index of constraint to check against all prior indices upto startind */
    11660 int* ndelconss /**< pointer to count number of deleted constraints */
    11661 )
    11662{
    11663 SCIP_CONS* cons0;
    11664 SCIP_CONSDATA* consdata0;
    11665 int c;
    11666
    11667 assert(scip != NULL);
    11668 assert(conss != NULL);
    11669 assert(firstchange <= chkind);
    11670 assert(ndelconss != NULL);
    11671
    11672 /* get the constraint to be checked against all prior constraints */
    11673 cons0 = conss[chkind];
    11674 assert(cons0 != NULL);
    11675 assert(SCIPconsIsActive(cons0));
    11676 assert(!SCIPconsIsModifiable(cons0));
    11677
    11678 consdata0 = SCIPconsGetData(cons0);
    11679 assert(consdata0 != NULL);
    11680 assert(consdata0->nvars >= 1);
    11681 assert(consdata0->merged);
    11682
    11683 /* sort the constraint */
    11684 sortItems(consdata0);
    11685
    11686 /* see #2970 */
    11687 if( consdata0->capacity == 0 )
    11688 return SCIP_OKAY;
    11689
    11690 /* check constraint against all prior constraints */
    11691 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
    11692 {
    11693 SCIP_CONS* cons1;
    11694 SCIP_CONSDATA* consdata1;
    11695 SCIP_Bool iscons0incons1contained;
    11696 SCIP_Bool iscons1incons0contained;
    11697 SCIP_Real quotient;
    11698 int v;
    11699 int v0;
    11700 int v1;
    11701
    11702 cons1 = conss[c];
    11703 assert(cons1 != NULL);
    11704 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
    11705 continue;
    11706
    11707 consdata1 = SCIPconsGetData(cons1);
    11708 assert(consdata1 != NULL);
    11709
    11710 /* if both constraints didn't change since last pair processing, we can ignore the pair */
    11711 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
    11712 continue;
    11713
    11714 assert(consdata1->nvars >= 1);
    11715 assert(consdata1->merged);
    11716
    11717 /* sort the constraint */
    11718 sortItems(consdata1);
    11719
    11720 /* see #2970 */
    11721 if( consdata1->capacity == 0 )
    11722 continue;
    11723
    11724 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
    11725
    11726 if( consdata0->nvars > consdata1->nvars )
    11727 {
    11728 iscons0incons1contained = FALSE;
    11729 iscons1incons0contained = TRUE;
    11730 v = consdata1->nvars - 1;
    11731 }
    11732 else if( consdata0->nvars < consdata1->nvars )
    11733 {
    11734 iscons0incons1contained = TRUE;
    11735 iscons1incons0contained = FALSE;
    11736 v = consdata0->nvars - 1;
    11737 }
    11738 else
    11739 {
    11740 iscons0incons1contained = TRUE;
    11741 iscons1incons0contained = TRUE;
    11742 v = consdata0->nvars - 1;
    11743 }
    11744
    11745 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
    11746
    11747 /* check consdata0 against consdata1:
    11748 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
    11749 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
    11750 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
    11751 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
    11752 */
    11753 v0 = consdata0->nvars - 1;
    11754 v1 = consdata1->nvars - 1;
    11755
    11756 while( v >= 0 )
    11757 {
    11758 assert(iscons0incons1contained || iscons1incons0contained);
    11759
    11760 /* now there are more variables in cons1 left */
    11761 if( v1 > v0 )
    11762 {
    11763 iscons1incons0contained = FALSE;
    11764 if( !iscons0incons1contained )
    11765 break;
    11766 }
    11767 /* now there are more variables in cons0 left */
    11768 else if( v1 < v0 )
    11769 {
    11770 iscons0incons1contained = FALSE;
    11771 if( !iscons1incons0contained )
    11772 break;
    11773 }
    11774
    11775 assert(v == v0 || v == v1);
    11776 assert(v0 >= 0);
    11777 assert(v1 >= 0);
    11778
    11779 /* both variables are the same */
    11780 if( consdata0->vars[v0] == consdata1->vars[v1] )
    11781 {
    11782 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
    11783 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
    11784 {
    11785 iscons1incons0contained = FALSE;
    11786 if( !iscons0incons1contained )
    11787 break;
    11788 }
    11789 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
    11790 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
    11791 {
    11792 iscons0incons1contained = FALSE;
    11793 if( !iscons1incons0contained )
    11794 break;
    11795 }
    11796 --v0;
    11797 --v1;
    11798 --v;
    11799 }
    11800 else
    11801 {
    11802 /* both constraints have a variables which is not part of the other constraint, so stop */
    11803 if( iscons0incons1contained && iscons1incons0contained )
    11804 {
    11805 iscons0incons1contained = FALSE;
    11806 iscons1incons0contained = FALSE;
    11807 break;
    11808 }
    11809 assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
    11810 assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
    11811 /* continue to the next variable */
    11812 if( iscons0incons1contained )
    11813 --v1;
    11814 else
    11815 --v0;
    11816 }
    11817 }
    11818 /* neither one constraint was contained in another or we checked all variables of one constraint against the
    11819 * other
    11820 */
    11821 assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
    11822
    11823 if( iscons1incons0contained )
    11824 {
    11825 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
    11826 SCIPdebugPrintCons(scip, cons1, NULL);
    11827
    11828 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
    11829 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
    11830
    11831 SCIP_CALL( SCIPdelCons(scip, cons1) );
    11832 ++(*ndelconss);
    11833 }
    11834 else if( iscons0incons1contained )
    11835 {
    11836 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
    11837 SCIPdebugPrintCons(scip, cons0, NULL);
    11838
    11839 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
    11840 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
    11841
    11842 SCIP_CALL( SCIPdelCons(scip, cons0) );
    11843 ++(*ndelconss);
    11844 break;
    11845 }
    11846 }
    11847
    11848 return SCIP_OKAY;
    11849}
    11850
    11851/** helper function to enforce constraints */
    11852static
    11854 SCIP* scip, /**< SCIP data structure */
    11855 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    11856 SCIP_CONS** conss, /**< constraints to process */
    11857 int nconss, /**< number of constraints */
    11858 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
    11859 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    11860 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    11861 )
    11862{
    11863 SCIP_CONSHDLRDATA* conshdlrdata;
    11864 SCIP_Bool violated;
    11865 SCIP_Bool cutoff = FALSE;
    11866 int maxncuts;
    11867 int ncuts = 0;
    11868 int i;
    11869
    11870 *result = SCIP_FEASIBLE;
    11871
    11872 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
    11873 sol == NULL ? "LP" : "relaxation");
    11874
    11875 /* get maximal number of cuts per round */
    11876 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11877 assert(conshdlrdata != NULL);
    11878 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
    11879
    11880 /* search for violated useful knapsack constraints */
    11881 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
    11882 {
    11883 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
    11884 if( violated )
    11885 {
    11886 /* add knapsack constraint as LP row to the relaxation */
    11887 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
    11888 ncuts++;
    11889 }
    11890 }
    11891
    11892 /* as long as no violations were found, search for violated obsolete knapsack constraints */
    11893 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
    11894 {
    11895 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
    11896 if( violated )
    11897 {
    11898 /* add knapsack constraint as LP row to the relaxation */
    11899 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
    11900 ncuts++;
    11901 }
    11902 }
    11903
    11904 /* adjust the result code */
    11905 if ( cutoff )
    11906 *result = SCIP_CUTOFF;
    11907 else if ( ncuts > 0 )
    11908 *result = SCIP_SEPARATED;
    11909
    11910 return SCIP_OKAY;
    11911}
    11912
    11913/*
    11914 * Linear constraint upgrading
    11915 */
    11916
    11917/** creates and captures a knapsack constraint out of a linear inequality */
    11918static
    11920 SCIP* scip, /**< SCIP data structure */
    11921 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    11922 const char* name, /**< name of constraint */
    11923 int nvars, /**< number of variables in the constraint */
    11924 SCIP_VAR** vars, /**< array with variables of constraint entries */
    11925 SCIP_Real* vals, /**< array with inequality coefficients */
    11926 SCIP_Real lhs, /**< left hand side of inequality */
    11927 SCIP_Real rhs, /**< right hand side of inequality */
    11928 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    11929 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    11930 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    11931 * Usually set to TRUE. */
    11932 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    11933 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    11934 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    11935 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    11936 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    11937 * Usually set to TRUE. */
    11938 SCIP_Bool local, /**< is constraint only valid locally?
    11939 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    11940 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    11941 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    11942 * adds coefficients to this constraint. */
    11943 SCIP_Bool dynamic, /**< is constraint subject to aging?
    11944 * Usually set to FALSE. Set to TRUE for own cuts which
    11945 * are separated as constraints. */
    11946 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    11947 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    11948 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    11949 * if it may be moved to a more global node?
    11950 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    11951 )
    11952{
    11953 SCIP_VAR** transvars;
    11954 SCIP_Longint* weights;
    11955 SCIP_Longint capacity;
    11956 SCIP_Longint weight;
    11957 int mult;
    11958 int v;
    11959
    11960 assert(nvars == 0 || vars != NULL);
    11961 assert(nvars == 0 || vals != NULL);
    11962 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
    11963
    11964 /* get temporary memory */
    11965 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
    11967
    11968 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
    11969 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
    11970 */
    11971 if( SCIPisInfinity(scip, rhs) )
    11972 {
    11973 mult = -1;
    11974 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
    11975 }
    11976 else
    11977 {
    11978 mult = +1;
    11979 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
    11980 }
    11981
    11982 /* negate positive or negative variables */
    11983 for( v = 0; v < nvars; ++v )
    11984 {
    11985 assert(SCIPisFeasIntegral(scip, vals[v]));
    11986 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
    11987 if( weight > 0 )
    11988 {
    11989 transvars[v] = vars[v];
    11990 weights[v] = weight;
    11991 }
    11992 else
    11993 {
    11994 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
    11995 weights[v] = -weight; /*lint !e2704*/
    11996 capacity -= weight;
    11997 }
    11998 assert(transvars[v] != NULL);
    11999 }
    12000
    12001 /* create the constraint */
    12002 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
    12003 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    12004
    12005 /* free temporary memory */
    12006 SCIPfreeBufferArray(scip, &weights);
    12007 SCIPfreeBufferArray(scip, &transvars);
    12008
    12009 return SCIP_OKAY;
    12010}
    12011
    12012/** tries to upgrade a linear constraint into a knapsack constraint */
    12013static
    12014SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
    12015{ /*lint --e{715}*/
    12016 SCIP_Bool upgrade;
    12017
    12018 assert(upgdcons != NULL);
    12019
    12020 /* check, if linear constraint can be upgraded to a knapsack constraint
    12021 * - all variables must be binary
    12022 * - all coefficients must be integral
    12023 * - exactly one of the sides must be infinite
    12024 * note that this includes the case of negative capacity, which has been
    12025 * observed to occur, e.g., when upgrading a conflict constraint
    12026 */
    12027 upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
    12028 && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
    12029 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
    12030
    12031 if( upgrade )
    12032 {
    12033 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
    12034
    12035 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
    12036 assert(!SCIPconsIsModifiable(cons));
    12037 SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
    12042 }
    12043
    12044 return SCIP_OKAY;
    12045}
    12046
    12047/** adds symmetry information of constraint to a symmetry detection graph */
    12048static
    12050 SCIP* scip, /**< SCIP pointer */
    12051 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
    12052 SCIP_CONS* cons, /**< constraint */
    12053 SYM_GRAPH* graph, /**< symmetry detection graph */
    12054 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
    12055 )
    12056{
    12057 SCIP_CONSDATA* consdata;
    12058 SCIP_VAR** vars;
    12059 SCIP_Real* vals;
    12060 SCIP_Real constant = 0.0;
    12061 SCIP_Real rhs;
    12062 int nlocvars;
    12063 int nvars;
    12064 int i;
    12065
    12066 assert(scip != NULL);
    12067 assert(cons != NULL);
    12068 assert(graph != NULL);
    12069 assert(success != NULL);
    12070
    12071 consdata = SCIPconsGetData(cons);
    12072 assert(consdata != NULL);
    12073 assert(graph != NULL);
    12074
    12075 /* get active variables of the constraint */
    12077 nlocvars = consdata->nvars;
    12078
    12081
    12082 for( i = 0; i < consdata->nvars; ++i )
    12083 {
    12084 vars[i] = consdata->vars[i];
    12085 vals[i] = (SCIP_Real) consdata->weights[i];
    12086 }
    12087
    12088 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
    12089 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
    12090
    12091 SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars,
    12092 cons, -SCIPinfinity(scip), rhs, success) );
    12093
    12094 SCIPfreeBufferArray(scip, &vals);
    12095 SCIPfreeBufferArray(scip, &vars);
    12096
    12097 return SCIP_OKAY;
    12098}
    12099
    12100/*
    12101 * Callback methods of constraint handler
    12102 */
    12103
    12104/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    12105/**! [SnippetConsCopyKnapsack] */
    12106static
    12107SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
    12108{ /*lint --e{715}*/
    12109 assert(scip != NULL);
    12110 assert(conshdlr != NULL);
    12111
    12113
    12114 /* call inclusion method of constraint handler */
    12116
    12117 *valid = TRUE;
    12118
    12119 return SCIP_OKAY;
    12120}
    12121/**! [SnippetConsCopyKnapsack] */
    12122
    12123/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    12124/**! [SnippetConsFreeKnapsack] */
    12125static
    12126SCIP_DECL_CONSFREE(consFreeKnapsack)
    12127{ /*lint --e{715}*/
    12128 SCIP_CONSHDLRDATA* conshdlrdata;
    12129
    12130 /* free constraint handler data */
    12131 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12132 assert(conshdlrdata != NULL);
    12133
    12134 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->probtoidxmap, conshdlrdata->probtoidxmapsize);
    12135 SCIPfreeBlockMemory(scip, &conshdlrdata);
    12136
    12137 SCIPconshdlrSetData(conshdlr, NULL);
    12138
    12139 return SCIP_OKAY;
    12140}
    12141/**! [SnippetConsFreeKnapsack] */
    12142
    12143
    12144/** initialization method of constraint handler (called after problem was transformed) */
    12145static
    12146SCIP_DECL_CONSINIT(consInitKnapsack)
    12147{ /*lint --e{715}*/
    12148 SCIP_CONSHDLRDATA* conshdlrdata;
    12149 int nvars;
    12150
    12151 assert( scip != NULL );
    12152 assert( conshdlr != NULL );
    12153
    12154 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12155 assert(conshdlrdata != NULL);
    12156
    12157 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
    12159
    12160 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
    12161 conshdlrdata->reals1size = nvars;
    12162
    12163 return SCIP_OKAY;
    12164}
    12165
    12166/** deinitialization method of constraint handler (called before transformed problem is freed) */
    12167static
    12168SCIP_DECL_CONSEXIT(consExitKnapsack)
    12169{ /*lint --e{715}*/
    12170 SCIP_CONSHDLRDATA* conshdlrdata;
    12171
    12172 assert( scip != NULL );
    12173 assert( conshdlr != NULL );
    12174
    12175 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12176 assert(conshdlrdata != NULL);
    12177
    12178 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
    12179 conshdlrdata->reals1size = 0;
    12180
    12181 return SCIP_OKAY;
    12182}
    12183
    12184
    12185/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    12186static
    12187SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
    12188{ /*lint --e{715}*/
    12189 SCIP_CONSHDLRDATA* conshdlrdata;
    12190 int nvars;
    12191
    12192 assert(scip != NULL);
    12193 assert(conshdlr != NULL);
    12194 assert(nconss == 0 || conss != NULL);
    12195
    12196 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12197 assert(conshdlrdata != NULL);
    12198
    12199 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
    12201
    12202 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
    12203 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
    12204 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
    12205 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
    12206 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
    12207 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
    12208 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
    12209 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
    12210
    12211 conshdlrdata->ints1size = nvars;
    12212 conshdlrdata->ints2size = nvars;
    12213 conshdlrdata->longints1size = nvars;
    12214 conshdlrdata->longints2size = nvars;
    12215 conshdlrdata->bools1size = nvars;
    12216 conshdlrdata->bools2size = nvars;
    12217 conshdlrdata->bools3size = nvars;
    12218 conshdlrdata->bools4size = nvars;
    12219
    12220#ifdef WITH_CARDINALITY_UPGRADE
    12221 conshdlrdata->upgradedcard = FALSE;
    12222#endif
    12223
    12224 return SCIP_OKAY;
    12225}
    12226
    12227
    12228/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
    12229static
    12230SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
    12231{ /*lint --e{715}*/
    12232 SCIP_CONSHDLRDATA* conshdlrdata;
    12233 int c;
    12234
    12235 assert(scip != NULL);
    12236 assert(conshdlr != NULL);
    12237
    12238 for( c = 0; c < nconss; ++c )
    12239 {
    12240 if( !SCIPconsIsDeleted(conss[c]) )
    12241 {
    12242 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
    12243 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
    12244 }
    12245 }
    12246
    12247 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12248 assert(conshdlrdata != NULL);
    12249
    12250 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
    12251 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
    12252 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
    12253 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
    12254 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
    12255 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
    12256 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
    12257 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
    12258
    12259 conshdlrdata->ints1size = 0;
    12260 conshdlrdata->ints2size = 0;
    12261 conshdlrdata->longints1size = 0;
    12262 conshdlrdata->longints2size = 0;
    12263 conshdlrdata->bools1size = 0;
    12264 conshdlrdata->bools2size = 0;
    12265 conshdlrdata->bools3size = 0;
    12266 conshdlrdata->bools4size = 0;
    12267
    12268 return SCIP_OKAY;
    12269}
    12270
    12271/** solving process initialization method of constraint handler */
    12272static
    12273SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
    12274{ /*lint --e{715}*/
    12275 /* add nlrow representation to NLP, if NLP had been constructed */
    12277 {
    12278 int c;
    12279 for( c = 0; c < nconss; ++c )
    12280 {
    12281 SCIP_CALL( addNlrow(scip, conss[c]) );
    12282 }
    12283 }
    12284
    12285 return SCIP_OKAY;
    12286}
    12287
    12288/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    12289static
    12290SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
    12291{ /*lint --e{715}*/
    12292 SCIP_CONSDATA* consdata;
    12293 int c;
    12294
    12295 assert( scip != NULL );
    12296
    12297 /* release the rows and nlrows of all constraints */
    12298 for( c = 0; c < nconss; ++c )
    12299 {
    12300 consdata = SCIPconsGetData(conss[c]);
    12301 assert(consdata != NULL);
    12302
    12303 if( consdata->row != NULL )
    12304 {
    12305 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
    12306 }
    12307
    12308 if( consdata->nlrow != NULL )
    12309 {
    12310 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
    12311 }
    12312 }
    12313
    12314 return SCIP_OKAY;
    12315}
    12316
    12317/** frees specific constraint data */
    12318static
    12319SCIP_DECL_CONSDELETE(consDeleteKnapsack)
    12320{ /*lint --e{715}*/
    12321 SCIP_CONSHDLRDATA* conshdlrdata;
    12322
    12323 assert(conshdlr != NULL);
    12324
    12326
    12327 /* get event handler */
    12328 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12329 assert(conshdlrdata != NULL);
    12330 assert(conshdlrdata->eventhdlr != NULL);
    12331
    12332 /* free knapsack constraint */
    12333 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
    12334
    12335 return SCIP_OKAY;
    12336}
    12337
    12338/** transforms constraint data into data belonging to the transformed problem */
    12339/**! [SnippetConsTransKnapsack]*/
    12340static
    12341SCIP_DECL_CONSTRANS(consTransKnapsack)
    12342{ /*lint --e{715}*/
    12343 SCIP_CONSHDLRDATA* conshdlrdata;
    12344 SCIP_CONSDATA* sourcedata;
    12345 SCIP_CONSDATA* targetdata;
    12346
    12347 assert(conshdlr != NULL);
    12349 assert(sourcecons != NULL);
    12350 assert(targetcons != NULL);
    12351
    12353
    12354 sourcedata = SCIPconsGetData(sourcecons);
    12355 assert(sourcedata != NULL);
    12356 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
    12357
    12358 /* get event handler */
    12359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12360 assert(conshdlrdata != NULL);
    12361 assert(conshdlrdata->eventhdlr != NULL);
    12362
    12363 /* create target constraint data */
    12364 SCIP_CALL( consdataCreate(scip, &targetdata,
    12365 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
    12366
    12367 /* create target constraint */
    12368 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
    12369 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
    12370 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
    12371 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
    12372 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
    12373
    12374 /* catch events for variables */
    12375 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
    12376
    12377 return SCIP_OKAY;
    12378}
    12379/**! [SnippetConsTransKnapsack]*/
    12380
    12381/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
    12382static
    12383SCIP_DECL_CONSINITLP(consInitlpKnapsack)
    12384{ /*lint --e{715}*/
    12385 int i;
    12386
    12387 *infeasible = FALSE;
    12388
    12389 for( i = 0; i < nconss && !(*infeasible); i++ )
    12390 {
    12391 assert(SCIPconsIsInitial(conss[i]));
    12392 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
    12393 }
    12394
    12395 return SCIP_OKAY;
    12396}
    12397
    12398/** separation method of constraint handler for LP solutions */
    12399static
    12400SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
    12401{ /*lint --e{715}*/
    12402 SCIP_CONSHDLRDATA* conshdlrdata;
    12403 SCIP_Bool sepacardinality;
    12404 SCIP_Bool cutoff;
    12405
    12406 SCIP_Real loclowerbound;
    12407 SCIP_Real glblowerbound;
    12408 SCIP_Real cutoffbound;
    12409 SCIP_Real maxbound;
    12410
    12411 int depth;
    12412 int nrounds;
    12413 int sepafreq;
    12414 int sepacardfreq;
    12415 int ncuts;
    12416 int maxsepacuts;
    12417 int i;
    12418
    12419 *result = SCIP_DIDNOTRUN;
    12420
    12421 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12422 assert(conshdlrdata != NULL);
    12423
    12424 depth = SCIPgetDepth(scip);
    12425 nrounds = SCIPgetNSepaRounds(scip);
    12426
    12427 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
    12428 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
    12429
    12430 /* only call the separator a given number of times at each node */
    12431 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
    12432 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
    12433 return SCIP_OKAY;
    12434
    12435 /* check, if we should additionally separate knapsack cuts */
    12436 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
    12437 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
    12438 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
    12439 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
    12440
    12441 /* check dual bound to see if we want to produce knapsack cuts at this node */
    12442 loclowerbound = SCIPgetLocalLowerbound(scip);
    12443 glblowerbound = SCIPgetLowerbound(scip);
    12444 cutoffbound = SCIPgetCutoffbound(scip);
    12445 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
    12446 sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
    12447 sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
    12448
    12449 /* get the maximal number of cuts allowed in a separation round */
    12450 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
    12451
    12452 *result = SCIP_DIDNOTFIND;
    12453 ncuts = 0;
    12454 cutoff = FALSE;
    12455
    12456 /* separate useful constraints */
    12457 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
    12458 {
    12459 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
    12460 }
    12461
    12462 /* adjust return value */
    12463 if ( cutoff )
    12464 *result = SCIP_CUTOFF;
    12465 else if ( ncuts > 0 )
    12466 *result = SCIP_SEPARATED;
    12467
    12468 return SCIP_OKAY;
    12469}
    12470
    12471
    12472/** separation method of constraint handler for arbitrary primal solutions */
    12473static
    12474SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
    12475{ /*lint --e{715}*/
    12476 SCIP_CONSHDLRDATA* conshdlrdata;
    12477 SCIP_Bool sepacardinality;
    12478 SCIP_Bool cutoff;
    12479
    12480 int depth;
    12481 int nrounds;
    12482 int sepafreq;
    12483 int sepacardfreq;
    12484 int ncuts;
    12485 int maxsepacuts;
    12486 int i;
    12487
    12488 *result = SCIP_DIDNOTRUN;
    12489
    12490 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12491 assert(conshdlrdata != NULL);
    12492
    12493 depth = SCIPgetDepth(scip);
    12494 nrounds = SCIPgetNSepaRounds(scip);
    12495
    12496 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
    12497 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
    12498
    12499 /* only call the separator a given number of times at each node */
    12500 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
    12501 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
    12502 return SCIP_OKAY;
    12503
    12504 /* check, if we should additionally separate knapsack cuts */
    12505 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
    12506 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
    12507 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
    12508 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
    12509
    12510 /* get the maximal number of cuts allowed in a separation round */
    12511 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
    12512
    12513 *result = SCIP_DIDNOTFIND;
    12514 ncuts = 0;
    12515 cutoff = FALSE;
    12516
    12517 /* separate useful constraints */
    12518 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
    12519 {
    12520 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
    12521 }
    12522
    12523 /* adjust return value */
    12524 if ( cutoff )
    12525 *result = SCIP_CUTOFF;
    12526 else if( ncuts > 0 )
    12527 *result = SCIP_SEPARATED;
    12528
    12529 return SCIP_OKAY;
    12530}
    12531
    12532/** constraint enforcing method of constraint handler for LP solutions */
    12533static
    12534SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
    12535{ /*lint --e{715}*/
    12536 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
    12537
    12538 return SCIP_OKAY;
    12539}
    12540
    12541/** constraint enforcing method of constraint handler for relaxation solutions */
    12542static
    12543SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
    12544{ /*lint --e{715}*/
    12545 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
    12546
    12547 return SCIP_OKAY;
    12548}
    12549
    12550/** constraint enforcing method of constraint handler for pseudo solutions */
    12551static
    12552SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
    12553{ /*lint --e{715}*/
    12554 SCIP_Bool violated;
    12555 int i;
    12556
    12557 for( i = 0; i < nconss; i++ )
    12558 {
    12559 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
    12560 if( violated )
    12561 {
    12562 *result = SCIP_INFEASIBLE;
    12563 return SCIP_OKAY;
    12564 }
    12565 }
    12566 *result = SCIP_FEASIBLE;
    12567
    12568 return SCIP_OKAY;
    12569}
    12570
    12571/** feasibility check method of constraint handler for integral solutions */
    12572static
    12573SCIP_DECL_CONSCHECK(consCheckKnapsack)
    12574{ /*lint --e{715}*/
    12575 SCIP_Bool violated;
    12576 int i;
    12577
    12578 *result = SCIP_FEASIBLE;
    12579
    12580 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
    12581 {
    12582 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
    12583 if( violated )
    12584 *result = SCIP_INFEASIBLE;
    12585 }
    12586
    12587 return SCIP_OKAY;
    12588}
    12589
    12590/** domain propagation method of constraint handler */
    12591static
    12592SCIP_DECL_CONSPROP(consPropKnapsack)
    12593{ /*lint --e{715}*/
    12594 SCIP_CONSHDLRDATA* conshdlrdata;
    12595 SCIP_Bool cutoff;
    12596 SCIP_Bool redundant;
    12597 SCIP_Bool inpresolve;
    12598 int nfixedvars;
    12599 int i;
    12600
    12601 cutoff = FALSE;
    12602 nfixedvars = 0;
    12603
    12604 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12605 assert(conshdlrdata != NULL);
    12606
    12607 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
    12608 assert(!inpresolve || SCIPinProbing(scip));
    12609
    12610 /* process useful constraints */
    12611 for( i = 0; i < nmarkedconss && !cutoff; i++ )
    12612 {
    12613 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
    12614 * otherwise the multi-aggregation should be resolved
    12615 */
    12616 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
    12617 continue;
    12618#ifndef NDEBUG
    12619 else
    12620 assert(!(SCIPconsGetData(conss[i])->existmultaggr));
    12621#endif
    12622
    12623 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
    12624
    12625 /* unmark the constraint to be propagated */
    12627 }
    12628
    12629 /* adjust result code */
    12630 if( cutoff )
    12631 *result = SCIP_CUTOFF;
    12632 else if( nfixedvars > 0 )
    12633 *result = SCIP_REDUCEDDOM;
    12634 else
    12635 *result = SCIP_DIDNOTFIND;
    12636
    12637 return SCIP_OKAY; /*lint !e438*/
    12638}
    12639
    12640/** presolving method of constraint handler */
    12641static
    12642SCIP_DECL_CONSPRESOL(consPresolKnapsack)
    12643{ /*lint --e{574,715}*/
    12644 SCIP_CONSHDLRDATA* conshdlrdata;
    12645 SCIP_CONSDATA* consdata;
    12646 SCIP_CONS* cons;
    12647 SCIP_Bool cutoff;
    12648 SCIP_Bool redundant;
    12649 SCIP_Bool success;
    12650 int oldnfixedvars;
    12651 int oldnchgbds;
    12652 int oldndelconss;
    12653 int oldnaddconss;
    12654 int oldnchgcoefs;
    12655 int oldnchgsides;
    12656 int firstchange;
    12657 int c;
    12658 SCIP_Bool newchanges;
    12659
    12660 /* remember old preprocessing counters */
    12661 cutoff = FALSE;
    12662 oldnfixedvars = *nfixedvars;
    12663 oldnchgbds = *nchgbds;
    12664 oldndelconss = *ndelconss;
    12665 oldnaddconss = *naddconss;
    12666 oldnchgcoefs = *nchgcoefs;
    12667 oldnchgsides = *nchgsides;
    12668 firstchange = INT_MAX;
    12669
    12670 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
    12671
    12672 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12673 assert(conshdlrdata != NULL);
    12674
    12675 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
    12676 {
    12677 int thisnfixedvars;
    12678 int thisnchgbds;
    12679
    12680 cons = conss[c];
    12681 consdata = SCIPconsGetData(cons);
    12682 assert(consdata != NULL);
    12683
    12684 /* update data structures */
    12685 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
    12686 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
    12687 {
    12688 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
    12689 if( cutoff )
    12690 break;
    12691 }
    12692
    12693 /* force presolving the constraint in the initial round */
    12694 if( nrounds == 0 )
    12695 consdata->presolvedtiming = 0;
    12696 else if( consdata->presolvedtiming >= presoltiming )
    12697 continue;
    12698
    12699 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
    12701 consdata->presolvedtiming = presoltiming;
    12702
    12703 thisnfixedvars = *nfixedvars;
    12704 thisnchgbds = *nchgbds;
    12705
    12706 /* merge constraint, so propagation works better */
    12707 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
    12708 if( cutoff )
    12709 break;
    12710
    12711 /* add cliques in the knapsack to the clique table */
    12712 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    12713 {
    12714 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
    12715 if( cutoff )
    12716 break;
    12717 }
    12718
    12719 /* propagate constraint */
    12720 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
    12721 {
    12722 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
    12723
    12724 if( cutoff )
    12725 break;
    12726 if( redundant )
    12727 {
    12728 (*ndelconss)++;
    12729 continue;
    12730 }
    12731 }
    12732
    12733 /* remove again all fixed variables, if further fixings were found */
    12734 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
    12735 {
    12736 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
    12737 if( cutoff )
    12738 break;
    12739
    12740 thisnfixedvars = *nfixedvars;
    12741 }
    12742
    12743 if( !SCIPconsIsModifiable(cons) )
    12744 {
    12745 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
    12746 if( consdata->weightsum <= consdata->capacity )
    12747 {
    12748 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
    12749 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
    12751 continue;
    12752 }
    12753
    12754 /* divide weights by their greatest common divisor */
    12755 normalizeWeights(cons, nchgcoefs, nchgsides);
    12756
    12757 /* try to simplify inequalities */
    12758 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
    12759 {
    12760 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
    12761 if( cutoff )
    12762 break;
    12763
    12764 if( SCIPconsIsDeleted(cons) )
    12765 continue;
    12766
    12767 /* remove again all fixed variables, if further fixings were found */
    12768 if( *nfixedvars > thisnfixedvars )
    12769 {
    12770 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
    12771 if( cutoff )
    12772 break;
    12773 }
    12774 }
    12775
    12776 /* tighten capacity and weights */
    12777 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
    12778 if( cutoff )
    12779 break;
    12780
    12781 if( SCIPconsIsActive(cons) )
    12782 {
    12783 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    12784 {
    12785 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
    12786 * dual reduction
    12787 */
    12788 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
    12789 if( redundant )
    12790 continue;
    12791 }
    12792
    12793 /* check if knapsack constraint is parallel to objective function */
    12794 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
    12795 }
    12796 }
    12797 /* remember the first changed constraint to begin the next aggregation round with */
    12798 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
    12799 firstchange = c;
    12800 }
    12801
    12802 /* preprocess pairs of knapsack constraints */
    12803 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
    12804 {
    12805 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
    12806 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
    12807 }
    12808
    12809 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
    12810 success = TRUE;
    12811 else
    12812 success = FALSE;
    12813
    12814 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
    12815 {
    12816 SCIP_Longint npaircomparisons;
    12817
    12818 npaircomparisons = 0;
    12819 oldndelconss = *ndelconss;
    12820 oldnchgsides = *nchgsides;
    12821 oldnchgcoefs = *nchgcoefs;
    12822
    12823 for( c = firstchange; c < nconss && !SCIPisStopped(scip); ++c )
    12824 {
    12825 cons = conss[c];
    12826 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
    12827 continue;
    12828
    12829 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
    12830
    12831 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
    12832
    12833 if( npaircomparisons > NMINCOMPARISONS )
    12834 {
    12835 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
    12836 success = TRUE;
    12837 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
    12838 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
    12839 break;
    12840 oldndelconss = *ndelconss;
    12841 oldnchgsides = *nchgsides;
    12842 oldnchgcoefs = *nchgcoefs;
    12843 npaircomparisons = 0;
    12844 }
    12845 }
    12846 }
    12847#ifdef WITH_CARDINALITY_UPGRADE
    12848 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
    12849 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
    12850 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
    12851 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
    12852 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
    12853 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
    12854 * as well, we better keep this code disabled. */
    12855 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
    12856 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
    12857 {
    12858 SCIP_HASHMAP* varhash;
    12859 SCIP_VAR** cardvars;
    12860 SCIP_Real* cardweights;
    12861 int noldupgdconss;
    12862 int nscipvars;
    12863 int makeupgrade;
    12864
    12865 noldupgdconss = *nupgdconss;
    12866 nscipvars = SCIPgetNVars(scip);
    12867 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
    12868 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
    12869
    12870 /* set up hash map */
    12871 SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
    12872
    12873 /* We loop through all cardinality constraints twice:
    12874 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
    12875 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
    12876 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
    12877 * - Second, upgrade knapsack constraints to cardinality constraints. */
    12878 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
    12879 {
    12880 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
    12881 {
    12882 SCIP_CONS* cardcons;
    12883 SCIP_VAR** vars;
    12884 SCIP_Longint* weights;
    12885 int nvars;
    12886 int v;
    12887
    12888 cons = conss[c];
    12889 assert( cons != NULL );
    12890
    12891 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
    12892 continue;
    12893
    12894 consdata = SCIPconsGetData(cons);
    12895 assert( consdata != NULL );
    12896
    12897 nvars = consdata->nvars;
    12898 vars = consdata->vars;
    12899 weights = consdata->weights;
    12900
    12901 /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
    12902 * - all variables must be binary (always true)
    12903 * - all coefficients must be 1.0
    12904 * - the right hand side must be smaller than nvars
    12905 */
    12906 if ( consdata->capacity >= nvars )
    12907 continue;
    12908
    12909 /* the weights are sorted: check first and last weight */
    12910 assert( consdata->sorted );
    12911 if ( weights[0] != 1 || weights[nvars-1] != 1 )
    12912 continue;
    12913
    12914 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
    12915 for (v = 0; v < nvars; ++v)
    12916 {
    12917 SCIP_BOUNDTYPE* impltypes;
    12918 SCIP_Real* implbounds;
    12919 SCIP_VAR** implvars;
    12920 SCIP_VAR* var;
    12921 int nimpls;
    12922 int j;
    12923
    12924 var = consdata->vars[v];
    12925 assert( var != NULL );
    12926 assert( SCIPvarIsBinary(var) );
    12927
    12928 /* ignore non-active variables */
    12929 if ( ! SCIPvarIsActive(var) )
    12930 break;
    12931
    12932 /* be sure that implication variable has zero objective */
    12933 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
    12934 break;
    12935
    12936 nimpls = SCIPvarGetNImpls(var, FALSE);
    12937 implvars = SCIPvarGetImplVars(var, FALSE);
    12938 implbounds = SCIPvarGetImplBounds(var, FALSE);
    12939 impltypes = SCIPvarGetImplTypes(var, FALSE);
    12940
    12941 for (j = 0; j < nimpls; ++j)
    12942 {
    12943 /* be sure that continuous variable is fixed to 0 */
    12944 if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
    12945 continue;
    12946
    12947 /* cannot currently deal with nonzero fixings */
    12948 if ( ! SCIPisZero(scip, implbounds[j]) )
    12949 continue;
    12950
    12951 /* number of down locks should be one */
    12952 if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
    12953 continue;
    12954
    12955 cardvars[v] = implvars[j];
    12956 cardweights[v] = (SCIP_Real) v;
    12957
    12958 break;
    12959 }
    12960
    12961 /* found no variable upper bound candidate -> exit */
    12962 if ( j >= nimpls )
    12963 break;
    12964 }
    12965
    12966 /* did not find fitting variable upper bound for some variable -> exit */
    12967 if ( v < nvars )
    12968 break;
    12969
    12970 /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
    12971 * in which the binary variable is involved in */
    12972 if ( makeupgrade == 0 )
    12973 {
    12974 for (v = 0; v < nvars; ++v)
    12975 {
    12976 if ( SCIPhashmapExists(varhash, vars[v]) )
    12977 {
    12978 int image;
    12979
    12980 image = SCIPhashmapGetImageInt(varhash, vars[v]);
    12981 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
    12982 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
    12983 }
    12984 else
    12985 {
    12986 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
    12987 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
    12988 assert( SCIPhashmapExists(varhash, vars[v]) );
    12989 }
    12990 }
    12991 }
    12992 else
    12993 {
    12994 SCIP_CONS* origcons;
    12995
    12996 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
    12997 * knapsack constraint coincides with the number of variable up locks */
    12998 for (v = 0; v < nvars; ++v)
    12999 {
    13000 assert( SCIPhashmapExists(varhash, vars[v]) );
    13001 if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
    13002 break;
    13003 }
    13004 if ( v < nvars )
    13005 break;
    13006
    13007 /* store that we have upgraded */
    13008 conshdlrdata->upgradedcard = TRUE;
    13009
    13010 /* at this point we found suitable variable upper bounds */
    13011 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
    13012
    13013 /* create cardinality constraint */
    13014 assert( ! SCIPconsIsModifiable(cons) );
    13015 SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
    13019#ifdef SCIP_DEBUG
    13020 SCIPprintCons(scip, cons, NULL);
    13021 SCIPinfoMessage(scip, NULL, "\n");
    13022 SCIPprintCons(scip, cardcons, NULL);
    13023 SCIPinfoMessage(scip, NULL, "\n");
    13024#endif
    13025 /* add the upgraded constraint to the problem */
    13026 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &cardcons) );
    13027 ++(*nupgdconss);
    13028
    13029 /* delete oknapsack constraint */
    13030 SCIP_CALL( SCIPdelCons(scip, cons) );
    13031 ++(*ndelconss);
    13032
    13033 /* We need to disable the original knapsack constraint, since it might happen that the binary variables
    13034 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
    13035 * although the cardinality constraint is satisfied. */
    13036 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
    13037 assert( origcons != NULL );
    13038 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
    13039
    13040 for (v = 0; v < nvars; ++v)
    13041 {
    13042 int image;
    13043
    13044 assert ( SCIPhashmapExists(varhash, vars[v]) );
    13045 image = SCIPhashmapGetImageInt(varhash, vars[v]);
    13046 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
    13047 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
    13048 }
    13049 }
    13050 }
    13051 }
    13052 SCIPhashmapFree(&varhash);
    13053 SCIPfreeBufferArray(scip, &cardweights);
    13054 SCIPfreeBufferArray(scip, &cardvars);
    13055
    13056 if ( *nupgdconss > noldupgdconss )
    13057 success = TRUE;
    13058 }
    13059#endif
    13060
    13061 if( cutoff )
    13062 *result = SCIP_CUTOFF;
    13063 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
    13064 *result = SCIP_SUCCESS;
    13065 else
    13066 *result = SCIP_DIDNOTFIND;
    13067
    13068 return SCIP_OKAY;
    13069}
    13070
    13071/** propagation conflict resolving method of constraint handler */
    13072static
    13073SCIP_DECL_CONSRESPROP(consRespropKnapsack)
    13074{ /*lint --e{715}*/
    13075 SCIP_CONSDATA* consdata;
    13076 SCIP_Longint capsum;
    13077 int i;
    13078
    13079 assert(result != NULL);
    13080
    13081 consdata = SCIPconsGetData(cons);
    13082 assert(consdata != NULL);
    13083
    13084 /* check if we fixed a binary variable to one (due to negated clique) */
    13085 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
    13086 {
    13087 for( i = 0; i < consdata->nvars; ++i )
    13088 {
    13089 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
    13090 {
    13091 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
    13092 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
    13093 break;
    13094 }
    13095 }
    13096 assert(i < consdata->nvars);
    13097 }
    13098 else
    13099 {
    13100 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
    13101 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
    13102 * knapsack constraint, see one above call of SCIPinferBinvarCons
    13103 */
    13104 if( inferinfo < 0 )
    13105 capsum = 0;
    13106 else
    13107 {
    13108 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
    13109 * inferinfo stores the position of the inference variable (but maybe the variables were re-sorted)
    13110 */
    13111 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
    13112 capsum = consdata->weights[inferinfo];
    13113 else
    13114 {
    13115 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
    13116 {}
    13117 assert(i < consdata->nvars);
    13118 capsum = consdata->weights[i];
    13119 }
    13120 }
    13121
    13122 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
    13123 * the capacity
    13124 */
    13125 if( capsum <= consdata->capacity )
    13126 {
    13127 for( i = 0; i < consdata->nvars; i++ )
    13128 {
    13129 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
    13130 {
    13131 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
    13132 capsum += consdata->weights[i];
    13133 if( capsum > consdata->capacity )
    13134 break;
    13135 }
    13136 }
    13137 }
    13138 }
    13139
    13140 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
    13141 * to zero can included negated clique information. A negated clique means, that at most one of the clique
    13142 * variables can be zero. These information can be used to compute a minimum activity of the constraint and
    13143 * used to fix variables to zero.
    13144 *
    13145 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
    13146 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
    13147 * one.
    13148 */
    13149 *result = SCIP_SUCCESS;
    13150
    13151 return SCIP_OKAY;
    13152}
    13153
    13154/** variable rounding lock method of constraint handler */
    13155/**! [SnippetConsLockKnapsack] */
    13156static
    13157SCIP_DECL_CONSLOCK(consLockKnapsack)
    13158{ /*lint --e{715}*/
    13159 SCIP_CONSDATA* consdata;
    13160 int i;
    13161
    13162 consdata = SCIPconsGetData(cons);
    13163 assert(consdata != NULL);
    13164
    13165 for( i = 0; i < consdata->nvars; i++)
    13166 {
    13167 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
    13168 }
    13169
    13170 return SCIP_OKAY;
    13171}
    13172/**! [SnippetConsLockKnapsack] */
    13173
    13174/** constraint activation notification method of constraint handler */
    13175static
    13176SCIP_DECL_CONSACTIVE(consActiveKnapsack)
    13177{ /*lint --e{715}*/
    13179 {
    13180 SCIP_CALL( addNlrow(scip, cons) );
    13181 }
    13182
    13183 return SCIP_OKAY;
    13184}
    13185
    13186/** constraint deactivation notification method of constraint handler */
    13187static
    13188SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
    13189{ /*lint --e{715}*/
    13190 SCIP_CONSDATA* consdata;
    13191
    13192 assert(cons != NULL);
    13193
    13194 consdata = SCIPconsGetData(cons);
    13195 assert(consdata != NULL);
    13196
    13197 /* remove row from NLP, if still in solving
    13198 * if we are in exitsolve, the whole NLP will be freed anyway
    13199 */
    13200 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
    13201 {
    13202 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
    13203 }
    13204
    13205 return SCIP_OKAY;
    13206}
    13207
    13208/** variable deletion method of constraint handler */
    13209static
    13210SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
    13211{
    13212 assert(scip != NULL);
    13213 assert(conshdlr != NULL);
    13214 assert(conss != NULL || nconss == 0);
    13215
    13216 if( nconss > 0 )
    13217 {
    13218 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
    13219 }
    13220
    13221 return SCIP_OKAY;
    13222}
    13223
    13224/** constraint display method of constraint handler */
    13225static
    13226SCIP_DECL_CONSPRINT(consPrintKnapsack)
    13227{ /*lint --e{715}*/
    13228 SCIP_CONSDATA* consdata;
    13229 int i;
    13230
    13231 assert( scip != NULL );
    13232 assert( conshdlr != NULL );
    13233 assert( cons != NULL );
    13234
    13235 consdata = SCIPconsGetData(cons);
    13236 assert(consdata != NULL);
    13237
    13238 for( i = 0; i < consdata->nvars; ++i )
    13239 {
    13240 if( i > 0 )
    13241 SCIPinfoMessage(scip, file, " ");
    13242 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
    13243 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
    13244 }
    13245 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
    13246
    13247 return SCIP_OKAY;
    13248}
    13249
    13250/** constraint copying method of constraint handler */
    13251static
    13252SCIP_DECL_CONSCOPY(consCopyKnapsack)
    13253{ /*lint --e{715}*/
    13254 SCIP_CONSHDLRDATA* conshdlrdata;
    13255 SCIP_VAR** sourcevars;
    13256 SCIP_Longint* weights;
    13257 const char* consname;
    13258 int nvars;
    13259
    13260 assert(scip != NULL);
    13261 assert(sourcescip != NULL);
    13262 assert(sourcecons != NULL);
    13263 assert(valid != NULL);
    13264
    13265 conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
    13266 assert(conshdlrdata != NULL);
    13267
    13268 /* get variables and weights of the source constraint */
    13269 sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
    13270 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
    13271 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
    13272
    13273 if( conshdlrdata->copytypedcons )
    13274 {
    13275 SCIP_VAR** targetvars;
    13276 int v;
    13277
    13278 *valid = TRUE;
    13279 assert(nvars >= 0);
    13280
    13281 /* allocate target variable array */
    13282 SCIP_CALL( SCIPallocBufferArray(scip, &targetvars, nvars) );
    13283
    13284 /* map source variables to target variables */
    13285 for( v = 0; v < nvars && *valid; ++v )
    13286 {
    13287 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &targetvars[v], varmap, consmap, global, valid) );
    13288 assert(!(*valid) || targetvars[v] != NULL);
    13289 }
    13290
    13291 /* only create the target constraint if all variables were successfully copied */
    13292 if( *valid )
    13293 {
    13294 if( name != NULL )
    13295 consname = name;
    13296 else
    13297 consname = SCIPconsGetName(sourcecons);
    13298
    13299 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, consname, nvars, targetvars, weights,
    13300 SCIPgetCapacityKnapsack(sourcescip, sourcecons),
    13301 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    13302 }
    13303
    13304 SCIPfreeBufferArray(scip, &targetvars);
    13305 }
    13306 else
    13307 {
    13308 SCIP_Real* coefs;
    13309 int v;
    13310
    13312 for( v = 0; v < nvars; ++v )
    13313 coefs[v] = (SCIP_Real) weights[v];
    13314
    13315 if( name != NULL )
    13316 consname = name;
    13317 else
    13318 consname = SCIPconsGetName(sourcecons);
    13319
    13320 /* copy the logic using the linear constraint copy method */
    13321 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
    13322 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
    13323 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
    13324 assert(cons != NULL);
    13325
    13326 SCIPfreeBufferArray(scip, &coefs);
    13327 }
    13328
    13329 return SCIP_OKAY;
    13330}
    13331
    13332/** constraint parsing method of constraint handler */
    13333static
    13334SCIP_DECL_CONSPARSE(consParseKnapsack)
    13335{ /*lint --e{715}*/
    13336 SCIP_VAR* var;
    13337 SCIP_Longint weight;
    13338 SCIP_VAR** vars;
    13339 SCIP_Longint* weights;
    13340 SCIP_Longint capacity;
    13341 char* endptr;
    13342 int nread;
    13343 int nvars;
    13344 int varssize;
    13345
    13346 assert(scip != NULL);
    13347 assert(success != NULL);
    13348 assert(str != NULL);
    13349 assert(name != NULL);
    13350 assert(cons != NULL);
    13351
    13352 *success = TRUE;
    13353
    13354 nvars = 0;
    13355 varssize = 5;
    13356 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
    13357 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
    13358
    13359 while( *str != '\0' )
    13360 {
    13361 /* try to parse coefficient, and use 1 if not successful */
    13362 weight = 1;
    13363 nread = 0;
    13364 (void) sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
    13365 str += nread;
    13366
    13367 /* parse variable name */
    13368 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
    13369
    13370 if( var == NULL )
    13371 {
    13372 endptr = strchr(endptr, '<');
    13373
    13374 if( endptr == NULL )
    13375 {
    13376 SCIPerrorMessage("no capacity found\n");
    13377 *success = FALSE;
    13378 }
    13379 else
    13380 str = endptr;
    13381
    13382 break;
    13383 }
    13384
    13385 str = endptr;
    13386
    13387 /* store weight and variable */
    13388 if( varssize <= nvars )
    13389 {
    13390 varssize = SCIPcalcMemGrowSize(scip, varssize+1);
    13391 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
    13392 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
    13393 }
    13394
    13395 vars[nvars] = var;
    13396 weights[nvars] = weight;
    13397 ++nvars;
    13398
    13399 /* skip whitespace */
    13400 SCIP_CALL( SCIPskipSpace((char**)&str) );
    13401 }
    13402
    13403 if( *success )
    13404 {
    13405 if( strncmp(str, "<=", 2) != 0 )
    13406 {
    13407 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
    13408 *success = FALSE;
    13409 }
    13410 else
    13411 {
    13412 str += 2;
    13413 }
    13414 }
    13415
    13416 if( *success )
    13417 {
    13418 /* skip whitespace */
    13419 SCIP_CALL( SCIPskipSpace((char**)&str) );
    13420
    13421 /* coverity[secure_coding] */
    13422 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
    13423 {
    13424 SCIPerrorMessage("error parsing capacity from '%s'\n", str);
    13425 *success = FALSE;
    13426 }
    13427 else
    13428 {
    13429 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
    13430 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    13431 }
    13432 }
    13433
    13434 SCIPfreeBufferArray(scip, &vars);
    13435 SCIPfreeBufferArray(scip, &weights);
    13436
    13437 return SCIP_OKAY;
    13438}
    13439
    13440/** constraint method of constraint handler which returns the variables (if possible) */
    13441static
    13442SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
    13443{ /*lint --e{715}*/
    13444 SCIP_CONSDATA* consdata;
    13445
    13446 consdata = SCIPconsGetData(cons);
    13447 assert(consdata != NULL);
    13448
    13449 if( varssize < consdata->nvars )
    13450 (*success) = FALSE;
    13451 else
    13452 {
    13453 assert(vars != NULL);
    13454
    13455 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
    13456 (*success) = TRUE;
    13457 }
    13458
    13459 return SCIP_OKAY;
    13460}
    13461
    13462/** constraint method of constraint handler which returns the number of variables (if possible) */
    13463static
    13464SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
    13465{ /*lint --e{715}*/
    13466 SCIP_CONSDATA* consdata;
    13467
    13468 consdata = SCIPconsGetData(cons);
    13469 assert(consdata != NULL);
    13470
    13471 (*nvars) = consdata->nvars;
    13472 (*success) = TRUE;
    13473
    13474 return SCIP_OKAY;
    13475}
    13476
    13477/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
    13478static
    13479SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
    13480{ /*lint --e{715}*/
    13481 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
    13482
    13483 return SCIP_OKAY;
    13484}
    13485
    13486/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
    13487static
    13488SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
    13489{ /*lint --e{715}*/
    13490 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
    13491
    13492 return SCIP_OKAY;
    13493}
    13494
    13495/*
    13496 * Event handler
    13497 */
    13498
    13499/** execution method of bound change event handler */
    13500static
    13501SCIP_DECL_EVENTEXEC(eventExecKnapsack)
    13502{ /*lint --e{715}*/
    13503 SCIP_CONSDATA* consdata;
    13504
    13505 assert(eventdata != NULL);
    13506 assert(eventdata->cons != NULL);
    13507
    13508 consdata = SCIPconsGetData(eventdata->cons);
    13509 assert(consdata != NULL);
    13510
    13511 switch( SCIPeventGetType(event) )
    13512 {
    13514 consdata->onesweightsum += eventdata->weight;
    13515 consdata->presolvedtiming = 0;
    13516 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
    13517 break;
    13519 consdata->onesweightsum -= eventdata->weight;
    13520 break;
    13522 consdata->presolvedtiming = 0;
    13523 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
    13524 break;
    13525 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
    13526 if( !consdata->existmultaggr )
    13527 {
    13528 SCIP_VAR* var;
    13529 var = SCIPeventGetVar(event);
    13530 assert(var != NULL);
    13531
    13532 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
    13534 {
    13535 consdata->existmultaggr = TRUE;
    13536 consdata->merged = FALSE;
    13537 }
    13540 consdata->merged = FALSE;
    13541 }
    13542 /*lint -fallthrough*/
    13543 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
    13544 consdata->presolvedtiming = 0;
    13545 break;
    13547 consdata->varsdeleted = TRUE;
    13548 break;
    13549 default:
    13550 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
    13551 return SCIP_INVALIDDATA;
    13552 }
    13553
    13554 return SCIP_OKAY;
    13555}
    13556
    13557
    13558/*
    13559 * constraint specific interface methods
    13560 */
    13561
    13562/** creates the handler for knapsack constraints and includes it in SCIP */
    13564 SCIP* scip /**< SCIP data structure */
    13565 )
    13566{
    13567 SCIP_EVENTHDLRDATA* eventhdlrdata;
    13568 SCIP_CONSHDLRDATA* conshdlrdata;
    13569 SCIP_CONSHDLR* conshdlr;
    13570
    13571 /* create knapsack constraint handler data */
    13572 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
    13573
    13574 /* include event handler for bound change events */
    13575 eventhdlrdata = NULL;
    13576 conshdlrdata->eventhdlr = NULL;
    13578 eventExecKnapsack, eventhdlrdata) );
    13579 conshdlrdata->probtoidxmap = NULL;
    13580 conshdlrdata->probtoidxmapsize = 0;
    13581
    13582 /* get event handler for bound change events */
    13583 if( conshdlrdata->eventhdlr == NULL )
    13584 {
    13585 SCIPerrorMessage("event handler for knapsack constraints not found\n");
    13586 return SCIP_PLUGINNOTFOUND;
    13587 }
    13588
    13589 /* include constraint handler */
    13592 consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
    13593 conshdlrdata) );
    13594
    13595 assert(conshdlr != NULL);
    13596
    13597 /* set non-fundamental callbacks via specific setter functions */
    13598 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
    13599 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
    13600 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
    13601 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
    13602 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
    13603 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
    13604 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
    13605 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
    13606 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
    13607 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
    13608 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
    13609 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
    13610 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
    13611 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
    13612 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
    13613 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
    13615 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
    13618 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
    13619 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
    13621 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
    13622 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
    13623 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) );
    13624 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) );
    13625
    13626 if( SCIPfindConshdlr(scip,"linear") != NULL )
    13627 {
    13628 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
    13630 }
    13631
    13632 /* add knapsack constraint handler parameters */
    13634 "constraints/" CONSHDLR_NAME "/sepacardfreq",
    13635 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
    13636 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
    13638 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
    13639 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
    13640 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
    13642 "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
    13643 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
    13644 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
    13646 "constraints/" CONSHDLR_NAME "/maxrounds",
    13647 "maximal number of separation rounds per node (-1: unlimited)",
    13648 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
    13650 "constraints/" CONSHDLR_NAME "/maxroundsroot",
    13651 "maximal number of separation rounds per node in the root node (-1: unlimited)",
    13652 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
    13654 "constraints/" CONSHDLR_NAME "/maxsepacuts",
    13655 "maximal number of cuts separated per separation round",
    13656 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
    13658 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
    13659 "maximal number of cuts separated per separation round in the root node",
    13660 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
    13662 "constraints/" CONSHDLR_NAME "/disaggregation",
    13663 "should disaggregation of knapsack constraints be allowed in preprocessing?",
    13664 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
    13666 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
    13667 "should presolving try to simplify knapsacks",
    13668 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
    13670 "constraints/" CONSHDLR_NAME "/negatedclique",
    13671 "should negated clique information be used in solving process",
    13672 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
    13674 "constraints/" CONSHDLR_NAME "/presolpairwise",
    13675 "should pairwise constraint comparison be performed in presolving?",
    13676 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
    13678 "constraints/" CONSHDLR_NAME "/presolusehashing",
    13679 "should hash table be used for detecting redundant constraints in advance",
    13680 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
    13682 "constraints/" CONSHDLR_NAME "/dualpresolving",
    13683 "should dual presolving steps be performed?",
    13684 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
    13686 "constraints/" CONSHDLR_NAME "/usegubs",
    13687 "should GUB information be used for separation?",
    13688 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
    13690 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
    13691 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
    13692 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
    13694 "constraints/" CONSHDLR_NAME "/detectlowerbound",
    13695 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
    13696 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
    13698 "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
    13699 "should clique partition information be updated when old partition seems outdated?",
    13700 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
    13702 "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
    13703 "factor on the growth of global cliques to decide when to update a previous "
    13704 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
    13705 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
    13706#ifdef WITH_CARDINALITY_UPGRADE
    13708 "constraints/" CONSHDLR_NAME "/upgdcardinality",
    13709 "if TRUE then try to update knapsack constraints to cardinality constraints",
    13710 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
    13711#endif
    13713 "constraints/" CONSHDLR_NAME "/copytypedcons",
    13714 "should knapsack constraints be copied as knapsack instead of as linear constraints?",
    13715 &conshdlrdata->copytypedcons, TRUE, DEFAULT_COPYTYPEDCONS, NULL, NULL) );
    13716
    13717 return SCIP_OKAY;
    13718}
    13719
    13720/** creates and captures a knapsack constraint
    13721 *
    13722 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13723 */
    13724/**! [SnippetConsCreationKnapsack] */
    13726 SCIP* scip, /**< SCIP data structure */
    13727 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13728 const char* name, /**< name of constraint */
    13729 int nvars, /**< number of items in the knapsack */
    13730 SCIP_VAR** vars, /**< array with item variables */
    13731 SCIP_Longint* weights, /**< array with item weights */
    13732 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
    13733 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    13734 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    13735 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    13736 * Usually set to TRUE. */
    13737 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    13738 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    13739 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    13740 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    13741 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    13742 * Usually set to TRUE. */
    13743 SCIP_Bool local, /**< is constraint only valid locally?
    13744 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    13745 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    13746 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    13747 * adds coefficients to this constraint. */
    13748 SCIP_Bool dynamic, /**< is constraint subject to aging?
    13749 * Usually set to FALSE. Set to TRUE for own cuts which
    13750 * are separated as constraints. */
    13751 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
    13752 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    13753 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
    13754 * if it may be moved to a more global node?
    13755 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
    13756 )
    13757{
    13758 SCIP_CONSHDLRDATA* conshdlrdata;
    13759 SCIP_CONSHDLR* conshdlr;
    13760 SCIP_CONSDATA* consdata;
    13761 int i;
    13762
    13763 /* find the knapsack constraint handler */
    13764 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    13765 if( conshdlr == NULL )
    13766 {
    13767 SCIPerrorMessage("knapsack constraint handler not found\n");
    13768 return SCIP_PLUGINNOTFOUND;
    13769 }
    13770
    13771 /* check whether all variables are binary */
    13772 assert(vars != NULL || nvars == 0);
    13773 for( i = 0; i < nvars; ++i )
    13774 {
    13775 if( !SCIPvarIsBinary(vars[i]) )
    13776 {
    13777 SCIPerrorMessage("item <%s> is not binary\n", SCIPvarGetName(vars[i]));
    13778 return SCIP_INVALIDDATA;
    13779 }
    13780 }
    13781
    13782 /* get event handler */
    13783 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13784 assert(conshdlrdata != NULL);
    13785 assert(conshdlrdata->eventhdlr != NULL);
    13786
    13787 /* create constraint data */
    13788 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
    13789
    13790 /* create constraint */
    13791 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    13792 local, modifiable, dynamic, removable, stickingatnode) );
    13793
    13794 /* catch events for variables */
    13795 if( SCIPisTransformed(scip) )
    13796 {
    13797 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
    13798 }
    13799
    13800 return SCIP_OKAY;
    13801}
    13802/**! [SnippetConsCreationKnapsack] */
    13803
    13804/** creates and captures a knapsack constraint
    13805 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
    13806 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
    13807 *
    13808 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
    13809 *
    13810 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13811 */
    13813 SCIP* scip, /**< SCIP data structure */
    13814 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13815 const char* name, /**< name of constraint */
    13816 int nvars, /**< number of items in the knapsack */
    13817 SCIP_VAR** vars, /**< array with item variables */
    13818 SCIP_Longint* weights, /**< array with item weights */
    13819 SCIP_Longint capacity /**< capacity of knapsack */
    13820 )
    13821{
    13822 assert(scip != NULL);
    13823
    13824 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
    13826
    13827 return SCIP_OKAY;
    13828}
    13829
    13830/** adds new item to knapsack constraint */
    13832 SCIP* scip, /**< SCIP data structure */
    13833 SCIP_CONS* cons, /**< constraint data */
    13834 SCIP_VAR* var, /**< item variable */
    13835 SCIP_Longint weight /**< item weight */
    13836 )
    13837{
    13838 assert(var != NULL);
    13839 assert(scip != NULL);
    13840
    13842
    13843 SCIP_CALL( addCoef(scip, cons, var, weight) );
    13844
    13845 return SCIP_OKAY;
    13846}
    13847
    13848/** gets the capacity of the knapsack constraint */
    13850 SCIP* scip, /**< SCIP data structure */
    13851 SCIP_CONS* cons /**< constraint data */
    13852 )
    13853{
    13854 SCIP_CONSDATA* consdata;
    13855
    13856 assert(scip != NULL);
    13857
    13859
    13860 consdata = SCIPconsGetData(cons);
    13861 assert(consdata != NULL);
    13862
    13863 return consdata->capacity;
    13864}
    13865
    13866/** changes capacity of the knapsack constraint
    13867 *
    13868 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
    13869 */
    13871 SCIP* scip, /**< SCIP data structure */
    13872 SCIP_CONS* cons, /**< constraint data */
    13873 SCIP_Longint capacity /**< new capacity of knapsack */
    13874 )
    13875{
    13876 SCIP_CONSDATA* consdata;
    13877
    13878 assert(scip != NULL);
    13879
    13881
    13883 {
    13884 SCIPerrorMessage("method can only be called during problem creation stage\n");
    13885 return SCIP_INVALIDDATA;
    13886 }
    13887
    13888 consdata = SCIPconsGetData(cons);
    13889 assert(consdata != NULL);
    13890
    13891 consdata->capacity = capacity;
    13892
    13893 return SCIP_OKAY;
    13894}
    13895
    13896/** gets the number of items in the knapsack constraint */
    13898 SCIP* scip, /**< SCIP data structure */
    13899 SCIP_CONS* cons /**< constraint data */
    13900 )
    13901{
    13902 SCIP_CONSDATA* consdata;
    13903
    13904 assert(scip != NULL);
    13905
    13907
    13908 consdata = SCIPconsGetData(cons);
    13909 assert(consdata != NULL);
    13910
    13911 return consdata->nvars;
    13912}
    13913
    13914/** gets the array of variables in the knapsack constraint; the user must not modify this array! */
    13916 SCIP* scip, /**< SCIP data structure */
    13917 SCIP_CONS* cons /**< constraint data */
    13918 )
    13919{
    13920 SCIP_CONSDATA* consdata;
    13921
    13922 assert(scip != NULL);
    13923
    13925
    13926 consdata = SCIPconsGetData(cons);
    13927 assert(consdata != NULL);
    13928
    13929 return consdata->vars;
    13930}
    13931
    13932/** gets the array of weights in the knapsack constraint; the user must not modify this array! */
    13934 SCIP* scip, /**< SCIP data structure */
    13935 SCIP_CONS* cons /**< constraint data */
    13936 )
    13937{
    13938 SCIP_CONSDATA* consdata;
    13939
    13940 assert(scip != NULL);
    13941
    13943
    13944 consdata = SCIPconsGetData(cons);
    13945 assert(consdata != NULL);
    13946
    13947 return consdata->weights;
    13948}
    13949
    13950/** gets the dual solution of the knapsack constraint in the current LP */
    13952 SCIP* scip, /**< SCIP data structure */
    13953 SCIP_CONS* cons /**< constraint data */
    13954 )
    13955{
    13956 SCIP_CONSDATA* consdata;
    13957
    13958 assert(scip != NULL);
    13959
    13961
    13962 consdata = SCIPconsGetData(cons);
    13963 assert(consdata != NULL);
    13964
    13965 if( consdata->row != NULL )
    13966 return SCIProwGetDualsol(consdata->row);
    13967 else
    13968 return 0.0;
    13969}
    13970
    13971/** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
    13973 SCIP* scip, /**< SCIP data structure */
    13974 SCIP_CONS* cons /**< constraint data */
    13975 )
    13976{
    13977 SCIP_CONSDATA* consdata;
    13978
    13979 assert(scip != NULL);
    13980
    13982
    13983 consdata = SCIPconsGetData(cons);
    13984 assert(consdata != NULL);
    13985
    13986 if( consdata->row != NULL )
    13987 return SCIProwGetDualfarkas(consdata->row);
    13988 else
    13989 return 0.0;
    13990}
    13991
    13992/** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
    13993 * the user must not modify the row!
    13994 */
    13996 SCIP* scip, /**< SCIP data structure */
    13997 SCIP_CONS* cons /**< constraint data */
    13998 )
    13999{
    14000 SCIP_CONSDATA* consdata;
    14001
    14002 assert(scip != NULL);
    14003
    14005
    14006 consdata = SCIPconsGetData(cons);
    14007 assert(consdata != NULL);
    14008
    14009 return consdata->row;
    14010}
    14011
    14012/** creates and returns the row of the given knapsack constraint */
    14014 SCIP* scip, /**< SCIP data structure */
    14015 SCIP_CONS* cons /**< constraint data */
    14016 )
    14017{
    14018 SCIP_CONSDATA* consdata;
    14019 int i;
    14020
    14021 assert(scip != NULL);
    14022
    14024
    14025 consdata = SCIPconsGetData(cons);
    14026 assert(consdata != NULL);
    14027 assert(consdata->row == NULL);
    14028
    14029 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
    14030 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
    14032
    14033 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
    14034 for( i = 0; i < consdata->nvars; ++i )
    14035 {
    14036 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
    14037 }
    14038 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
    14039
    14040 return SCIP_OKAY;
    14041}
    14042
    14043/** cleans up (multi-)aggregations and fixings from knapsack constraints */
    14045 SCIP* scip, /**< SCIP data structure */
    14046 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
    14047 SCIP_Bool* infeasible, /**< pointer to return whether the problem was detected to be infeasible */
    14048 int* ndelconss /**< pointer to count number of deleted constraints */
    14049 )
    14050{
    14051 SCIP_CONSHDLR* conshdlr;
    14052 SCIP_CONS** conss;
    14053 int nconss;
    14054 int i;
    14055
    14056 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    14057 if( conshdlr == NULL )
    14058 return SCIP_OKAY;
    14059
    14060 assert(infeasible != NULL);
    14061 *infeasible = FALSE;
    14062
    14063 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
    14064 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
    14065
    14066 /* loop backwards since then deleted constraints do not interfere with the loop */
    14067 for( i = nconss - 1; i >= 0; --i )
    14068 {
    14069 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
    14070
    14071 if( *infeasible )
    14072 break;
    14073
    14074 if( SCIPconsGetData(conss[i])->nvars >= 1 )
    14075 continue;
    14076
    14077 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
    14078 ++(*ndelconss);
    14079 }
    14080
    14081 return SCIP_OKAY;
    14082}
    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:92
    #define DEFAULT_SEPACARDFREQ
    #define CONSHDLR_SEPAFREQ
    Definition: cons_knapsack.c:85
    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:84
    static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
    #define CONSHDLR_DESC
    Definition: cons_knapsack.c:81
    #define DEFAULT_COPYTYPEDCONS
    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:95
    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:89
    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:82
    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:86
    #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:94
    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:87
    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:98
    #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:83
    #define MAXABSVBCOEF
    static SCIP_DECL_CONSPARSE(consParseKnapsack)
    #define LINCONSUPGD_PRIORITY
    #define CONSHDLR_DELAYSEPA
    Definition: cons_knapsack.c:90
    #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:80
    #define EVENTHDLR_NAME
    Definition: cons_knapsack.c:97
    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:91
    static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
    #define EVENTTYPE_KNAPSACK
    Definition: cons_knapsack.c:99
    #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:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:306
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_LONGINT_MAX
    Definition: def.h:151
    #define SCIP_CALL(x)
    Definition: def.h:364
    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:9551
    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_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
    Definition: scip_copy.c:713
    SCIP_Bool SCIPisTransformed(SCIP *scip)
    Definition: scip_general.c:655
    SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
    Definition: scip_general.c:676
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    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:1844
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
    Definition: scip_sol.c:467
    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:24514
    SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
    Definition: var.c:23566
    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:23875
    SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24536
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23674
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    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:24600
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23418
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4380
    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:24300
    SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
    Definition: var.c:23462
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
    Definition: var.c:17595
    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:24174
    SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24617
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23684
    SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
    Definition: scip_var.c:5118
    SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
    Definition: scip_var.c:5296
    SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
    Definition: scip_var.c:2872
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23694
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_RETCODE 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:24546
    int SCIPvarGetNVubs(SCIP_VAR *var)
    Definition: var.c:24556
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23522
    SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24646
    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:23838
    int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
    Definition: var.c:23826
    int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24674
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
    Definition: var.c:23475
    int SCIPgetNCliques(SCIP *scip)
    Definition: scip_var.c:9512
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24526
    SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24685
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    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:17319
    SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
    Definition: var.c:17687
    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:24588
    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:24568
    SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
    Definition: var.c:16852
    SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
    Definition: var.c:24578
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4322
    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:24632
    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:17655
    SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
    Definition: var.c:23850
    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 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:1219
    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_INVALIDCALL
    Definition: type_retcode.h:51
    @ 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