1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2 /* */ 3 /* This file is part of the program and library */ 4 /* SCIP --- Solving Constraint Integer Programs */ 5 /* */ 6 /* Copyright (c) 2002-2023 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 37 #include "blockmemshell/memory.h" 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" 48 #include "scip/pub_misc_select.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" 68 #include "scip/scip_solvingstats.h" 69 #include "scip/scip_tree.h" 70 #include "scip/scip_var.h" 71 #include "scip/symmetry_graph.h" 72 #include "symmetry/struct_symmetry.h" 73 #include <ctype.h> 74 #include <string.h> 75 76 #ifdef WITH_CARDINALITY_UPGRADE 77 #include "scip/cons_cardinality.h" 78 #endif 79 80 /* constraint handler properties */ 81 #define CONSHDLR_NAME "knapsack" 82 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0" 83 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */ 84 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */ 85 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */ 86 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */ 87 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */ 88 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation, 89 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */ 90 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */ 91 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */ 92 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */ 93 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */ 94 95 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS 96 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP 97 98 #define EVENTHDLR_NAME "knapsack" 99 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints" 100 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \ 101 | SCIP_EVENTTYPE_UBTIGHTENED \ 102 | SCIP_EVENTTYPE_VARFIXED \ 103 | SCIP_EVENTTYPE_VARDELETED \ 104 | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */ 105 106 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */ 107 108 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */ 109 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */ 110 111 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */ 112 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */ 113 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */ 114 115 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */ 116 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */ 117 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */ 118 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */ 119 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */ 120 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared 121 * to best node's dual bound for separating knapsack cuts */ 122 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */ 123 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */ 124 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */ 125 126 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */ 127 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */ 128 129 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */ 130 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */ 131 132 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */ 133 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */ 134 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise 135 * comparison round */ 136 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */ 137 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective 138 * function defining an upper bound and prevent these constraints from 139 * entering the LP */ 140 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective 141 * function defining a lower bound and prevent these constraints from 142 * entering the LP */ 143 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */ 144 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */ 145 146 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */ 147 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */ 148 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */ 149 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous 150 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */ 151 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */ 152 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */ 153 #ifdef WITH_CARDINALITY_UPGRADE 154 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */ 155 #endif 156 157 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */ 158 159 /* 160 * Data structures 161 */ 162 163 /** constraint handler data */ 164 struct 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 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */ 194 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared 195 * to best node's dual bound for separating knapsack cuts */ 196 int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */ 197 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */ 198 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */ 199 int maxsepacuts; /**< maximal number of cuts separated per separation round */ 200 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */ 201 SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */ 202 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */ 203 SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */ 204 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */ 205 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */ 206 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */ 207 SCIP_Bool usegubs; /**< should GUB information be used for separation? */ 208 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective 209 * function defining an upper bound and prevent these constraints from 210 * entering the LP */ 211 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective 212 * function defining a lower bound and prevent these constraints from 213 * entering the LP */ 214 SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */ 215 SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */ 216 SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous 217 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */ 218 #ifdef WITH_CARDINALITY_UPGRADE 219 SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */ 220 SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */ 221 #endif 222 }; 223 224 225 /** constraint data for knapsack constraints */ 226 struct SCIP_ConsData 227 { 228 SCIP_VAR** vars; /**< variables in knapsack constraint */ 229 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */ 230 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */ 231 int* cliquepartition; /**< clique indices of the clique partition */ 232 int* negcliquepartition; /**< clique indices of the negated clique partition */ 233 SCIP_ROW* row; /**< corresponding LP row */ 234 SCIP_NLROW* nlrow; /**< corresponding NLP row */ 235 int nvars; /**< number of variables in knapsack constraint */ 236 int varssize; /**< size of vars, weights, and eventdata arrays */ 237 int ncliques; /**< number of cliques in the clique partition */ 238 int nnegcliques; /**< number of cliques in the negated clique partition */ 239 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */ 240 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */ 241 SCIP_Longint capacity; /**< capacity of knapsack */ 242 SCIP_Longint weightsum; /**< sum of all weights */ 243 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */ 244 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */ 245 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */ 246 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */ 247 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */ 248 unsigned int merged:1; /**< are the constraint's equal variables already merged? */ 249 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */ 250 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */ 251 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */ 252 }; 253 254 /** event data for bound changes events */ 255 struct SCIP_EventData 256 { 257 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */ 258 SCIP_Longint weight; /**< weight of variable */ 259 int filterpos; /**< position of event in variable's event filter */ 260 }; 261 262 263 /** data structure to combine two sorting key values */ 264 struct sortkeypair 265 { 266 SCIP_Real key1; /**< first sort key value */ 267 SCIP_Real key2; /**< second sort key value */ 268 }; 269 typedef struct sortkeypair SORTKEYPAIR; 270 271 /** status of GUB constraint */ 272 enum GUBVarstatus 273 { 274 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */ 275 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */ 276 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */ 277 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */ 278 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */ 279 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */ 280 }; 281 typedef enum GUBVarstatus GUBVARSTATUS; 282 283 /** status of variable in GUB constraint */ 284 enum GUBConsstatus 285 { 286 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */ 287 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */ 288 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */ 289 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */ 290 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */ 291 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */ 292 }; 293 typedef enum GUBConsstatus GUBCONSSTATUS; 294 295 /** data structure of GUB constraints */ 296 struct SCIP_GUBCons 297 { 298 int* gubvars; /**< indices of GUB variables in knapsack constraint */ 299 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */ 300 int ngubvars; /**< number of GUB variables */ 301 int gubvarssize; /**< size of gubvars array */ 302 }; 303 typedef struct SCIP_GUBCons SCIP_GUBCONS; 304 305 /** data structure of a set of GUB constraints */ 306 struct SCIP_GUBSet 307 { 308 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */ 309 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */ 310 int ngubconss; /**< number of GUB constraints */ 311 int nvars; /**< number of variables in knapsack constraint */ 312 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */ 313 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */ 314 }; 315 typedef struct SCIP_GUBSet SCIP_GUBSET; 316 317 /* 318 * Local methods 319 */ 320 321 /** comparison method for two sorting key pairs */ 322 static 323 SCIP_DECL_SORTPTRCOMP(compSortkeypairs) 324 { 325 SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1; 326 SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2; 327 328 if( sortkeypair1->key1 < sortkeypair2->key1 ) 329 return -1; 330 else if( sortkeypair1->key1 > sortkeypair2->key1 ) 331 return +1; 332 else if( sortkeypair1->key2 < sortkeypair2->key2 ) 333 return -1; 334 else if( sortkeypair1->key2 > sortkeypair2->key2 ) 335 return +1; 336 else 337 return 0; 338 } 339 340 /** creates event data */ 341 static 342 SCIP_RETCODE eventdataCreate( 343 SCIP* scip, /**< SCIP data structure */ 344 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */ 345 SCIP_CONS* cons, /**< constraint */ 346 SCIP_Longint weight /**< weight of variable */ 347 ) 348 { 349 assert(eventdata != NULL); 350 351 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) ); 352 (*eventdata)->cons = cons; 353 (*eventdata)->weight = weight; 354 355 return SCIP_OKAY; 356 } 357 358 /** frees event data */ 359 static 360 SCIP_RETCODE eventdataFree( 361 SCIP* scip, /**< SCIP data structure */ 362 SCIP_EVENTDATA** eventdata /**< pointer to event data */ 363 ) 364 { 365 assert(eventdata != NULL); 366 367 SCIPfreeBlockMemory(scip, eventdata); 368 369 return SCIP_OKAY; 370 } 371 372 /** sorts items in knapsack with nonincreasing weights */ 373 static 374 void sortItems( 375 SCIP_CONSDATA* consdata /**< constraint data */ 376 ) 377 { 378 assert(consdata != NULL); 379 assert(consdata->nvars == 0 || consdata->vars != NULL); 380 assert(consdata->nvars == 0 || consdata->weights != NULL); 381 assert(consdata->nvars == 0 || consdata->eventdata != NULL); 382 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL)); 383 384 if( !consdata->sorted ) 385 { 386 int pos; 387 int lastcliquenum; 388 int v; 389 390 /* sort of five joint arrays of Long/pointer/pointer/ints/ints, 391 * sorted by first array in non-increasing order via sort template */ 392 SCIPsortDownLongPtrPtrIntInt( 393 consdata->weights, 394 (void**)consdata->vars, 395 (void**)consdata->eventdata, 396 consdata->cliquepartition, 397 consdata->negcliquepartition, 398 consdata->nvars); 399 400 v = consdata->nvars - 1; 401 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */ 402 while( v >= 0 ) 403 { 404 int w = v - 1; 405 406 while( w >= 0 && consdata->weights[v] == consdata->weights[w] ) 407 --w; 408 409 if( v - w > 1 ) 410 { 411 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */ 412 SCIPsortPtrPtrIntInt( 413 (void**)(&(consdata->vars[w+1])), 414 (void**)(&(consdata->eventdata[w+1])), 415 &(consdata->cliquepartition[w+1]), 416 &(consdata->negcliquepartition[w+1]), 417 SCIPvarComp, 418 v - w); 419 } 420 v = w; 421 } 422 423 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */ 424 if( consdata->cliquepartitioned ) 425 { 426 lastcliquenum = 0; 427 428 for( pos = 0; pos < consdata->nvars; ++pos ) 429 { 430 /* if the clique number in the normal clique at position pos is greater than the last found clique number the 431 * partition is invalid */ 432 if( consdata->cliquepartition[pos] > lastcliquenum ) 433 { 434 consdata->cliquepartitioned = FALSE; 435 break; 436 } 437 else if( consdata->cliquepartition[pos] == lastcliquenum ) 438 ++lastcliquenum; 439 } 440 } 441 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */ 442 if( consdata->negcliquepartitioned ) 443 { 444 lastcliquenum = 0; 445 446 for( pos = 0; pos < consdata->nvars; ++pos ) 447 { 448 /* if the clique number in the negated clique at position pos is greater than the last found clique number the 449 * partition is invalid */ 450 if( consdata->negcliquepartition[pos] > lastcliquenum ) 451 { 452 consdata->negcliquepartitioned = FALSE; 453 break; 454 } 455 else if( consdata->negcliquepartition[pos] == lastcliquenum ) 456 ++lastcliquenum; 457 } 458 } 459 460 consdata->sorted = TRUE; 461 } 462 #ifndef NDEBUG 463 { 464 /* check if the weight array is sorted in a non-increasing way */ 465 int i; 466 for( i = 0; i < consdata->nvars-1; ++i ) 467 assert(consdata->weights[i] >= consdata->weights[i+1]); 468 } 469 #endif 470 } 471 472 /** calculates a partition of the variables into cliques */ 473 static 474 SCIP_RETCODE calcCliquepartition( 475 SCIP* scip, /**< SCIP data structure */ 476 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */ 477 SCIP_CONSDATA* consdata, /**< constraint data */ 478 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */ 479 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */ 480 ) 481 { 482 SCIP_Bool ispartitionoutdated; 483 SCIP_Bool isnegpartitionoutdated; 484 assert(consdata != NULL); 485 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL)); 486 487 /* rerun eventually if number of global cliques increased considerably since last partition */ 488 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1 489 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart)); 490 491 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) ) 492 { 493 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) ); 494 consdata->cliquepartitioned = TRUE; 495 consdata->ncliqueslastpart = SCIPgetNCliques(scip); 496 } 497 498 /* rerun eventually if number of global cliques increased considerably since last negated partition */ 499 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1 500 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart)); 501 502 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) ) 503 { 504 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) ); 505 consdata->negcliquepartitioned = TRUE; 506 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip); 507 } 508 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars); 509 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars); 510 511 return SCIP_OKAY; 512 } 513 514 /** installs rounding locks for the given variable in the given knapsack constraint */ 515 static 516 SCIP_RETCODE lockRounding( 517 SCIP* scip, /**< SCIP data structure */ 518 SCIP_CONS* cons, /**< knapsack constraint */ 519 SCIP_VAR* var /**< variable of constraint entry */ 520 ) 521 { 522 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) ); 523 524 return SCIP_OKAY; 525 } 526 527 /** removes rounding locks for the given variable in the given knapsack constraint */ 528 static 529 SCIP_RETCODE unlockRounding( 530 SCIP* scip, /**< SCIP data structure */ 531 SCIP_CONS* cons, /**< knapsack constraint */ 532 SCIP_VAR* var /**< variable of constraint entry */ 533 ) 534 { 535 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) ); 536 537 return SCIP_OKAY; 538 } 539 540 /** catches bound change events for variables in knapsack */ 541 static 542 SCIP_RETCODE catchEvents( 543 SCIP* scip, /**< SCIP data structure */ 544 SCIP_CONS* cons, /**< constraint */ 545 SCIP_CONSDATA* consdata, /**< constraint data */ 546 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */ 547 ) 548 { 549 int i; 550 551 assert(cons != NULL); 552 assert(consdata != NULL); 553 assert(consdata->nvars == 0 || consdata->vars != NULL); 554 assert(consdata->nvars == 0 || consdata->weights != NULL); 555 assert(consdata->nvars == 0 || consdata->eventdata != NULL); 556 557 for( i = 0; i < consdata->nvars; i++) 558 { 559 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) ); 560 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK, 561 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) ); 562 } 563 564 return SCIP_OKAY; 565 } 566 567 /** drops bound change events for variables in knapsack */ 568 static 569 SCIP_RETCODE dropEvents( 570 SCIP* scip, /**< SCIP data structure */ 571 SCIP_CONSDATA* consdata, /**< constraint data */ 572 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */ 573 ) 574 { 575 int i; 576 577 assert(consdata != NULL); 578 assert(consdata->nvars == 0 || consdata->vars != NULL); 579 assert(consdata->nvars == 0 || consdata->weights != NULL); 580 assert(consdata->nvars == 0 || consdata->eventdata != NULL); 581 582 for( i = 0; i < consdata->nvars; i++) 583 { 584 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK, 585 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) ); 586 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) ); 587 } 588 589 return SCIP_OKAY; 590 } 591 592 /** ensures, that vars and vals arrays can store at least num entries */ 593 static 594 SCIP_RETCODE consdataEnsureVarsSize( 595 SCIP* scip, /**< SCIP data structure */ 596 SCIP_CONSDATA* consdata, /**< knapsack constraint data */ 597 int num, /**< minimum number of entries to store */ 598 SCIP_Bool transformed /**< is constraint from transformed problem? */ 599 ) 600 { 601 assert(consdata != NULL); 602 assert(consdata->nvars <= consdata->varssize); 603 604 if( num > consdata->varssize ) 605 { 606 int newsize; 607 608 newsize = SCIPcalcMemGrowSize(scip, num); 609 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) ); 610 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) ); 611 if( transformed ) 612 { 613 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) ); 614 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) ); 615 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) ); 616 } 617 else 618 { 619 assert(consdata->eventdata == NULL); 620 assert(consdata->cliquepartition == NULL); 621 assert(consdata->negcliquepartition == NULL); 622 } 623 consdata->varssize = newsize; 624 } 625 assert(num <= consdata->varssize); 626 627 return SCIP_OKAY; 628 } 629 630 /** updates all weight sums for fixed and unfixed variables */ 631 static 632 void updateWeightSums( 633 SCIP_CONSDATA* consdata, /**< knapsack constraint data */ 634 SCIP_VAR* var, /**< variable for this weight */ 635 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */ 636 ) 637 { 638 assert(consdata != NULL); 639 assert(var != NULL); 640 641 consdata->weightsum += weightdelta; 642 643 if( SCIPvarGetLbLocal(var) > 0.5 ) 644 consdata->onesweightsum += weightdelta; 645 646 assert(consdata->weightsum >= 0); 647 assert(consdata->onesweightsum >= 0); 648 } 649 650 /** creates knapsack constraint data */ 651 static 652 SCIP_RETCODE consdataCreate( 653 SCIP* scip, /**< SCIP data structure */ 654 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */ 655 int nvars, /**< number of variables in knapsack */ 656 SCIP_VAR** vars, /**< variables of knapsack */ 657 SCIP_Longint* weights, /**< weights of knapsack items */ 658 SCIP_Longint capacity /**< capacity of knapsack */ 659 ) 660 { 661 int v; 662 SCIP_Longint constant; 663 664 assert(consdata != NULL); 665 666 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) ); 667 668 constant = 0L; 669 (*consdata)->vars = NULL; 670 (*consdata)->weights = NULL; 671 (*consdata)->nvars = 0; 672 if( nvars > 0 ) 673 { 674 SCIP_VAR** varsbuffer; 675 SCIP_Longint* weightsbuffer; 676 int k; 677 678 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) ); 679 SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) ); 680 681 k = 0; 682 for( v = 0; v < nvars; ++v ) 683 { 684 assert(vars[v] != NULL); 685 assert(SCIPvarIsBinary(vars[v])); 686 687 /* all weight have to be non negative */ 688 assert( weights[v] >= 0 ); 689 690 if( weights[v] > 0 ) 691 { 692 /* treat fixed variables as constants if problem compression is enabled */ 693 if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 ) 694 { 695 /* only if the variable is fixed to 1, we add its weight to the constant */ 696 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 ) 697 constant += weights[v]; 698 } 699 else 700 { 701 varsbuffer[k] = vars[v]; 702 weightsbuffer[k] = weights[v]; 703 ++k; 704 } 705 } 706 } 707 assert(k >= 0); 708 assert(constant >= 0); 709 710 (*consdata)->nvars = k; 711 712 /* copy the active variables and weights into the constraint data structure */ 713 if( k > 0 ) 714 { 715 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) ); 716 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) ); 717 } 718 719 /* free buffer storage */ 720 SCIPfreeBufferArray(scip, &weightsbuffer); 721 SCIPfreeBufferArray(scip, &varsbuffer); 722 } 723 724 (*consdata)->varssize = (*consdata)->nvars; 725 (*consdata)->capacity = capacity - constant; 726 (*consdata)->eventdata = NULL; 727 (*consdata)->cliquepartition = NULL; 728 (*consdata)->negcliquepartition = NULL; 729 (*consdata)->row = NULL; 730 (*consdata)->nlrow = NULL; 731 (*consdata)->weightsum = 0; 732 (*consdata)->onesweightsum = 0; 733 (*consdata)->ncliques = 0; 734 (*consdata)->nnegcliques = 0; 735 (*consdata)->presolvedtiming = 0; 736 (*consdata)->sorted = FALSE; 737 (*consdata)->cliquepartitioned = FALSE; 738 (*consdata)->negcliquepartitioned = FALSE; 739 (*consdata)->ncliqueslastpart = -1; 740 (*consdata)->ncliqueslastnegpart = -1; 741 (*consdata)->merged = FALSE; 742 (*consdata)->cliquesadded = FALSE; 743 (*consdata)->varsdeleted = FALSE; 744 (*consdata)->existmultaggr = FALSE; 745 746 /* get transformed variables, if we are in the transformed problem */ 747 if( SCIPisTransformed(scip) ) 748 { 749 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) ); 750 751 for( v = 0; v < (*consdata)->nvars; v++ ) 752 { 753 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]); 754 assert(var != NULL); 755 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); 756 } 757 758 /* allocate memory for additional data structures */ 759 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) ); 760 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) ); 761 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) ); 762 } 763 764 /* calculate sum of weights and capture variables */ 765 for( v = 0; v < (*consdata)->nvars; ++v ) 766 { 767 /* calculate sum of weights */ 768 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]); 769 770 /* capture variables */ 771 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) ); 772 } 773 return SCIP_OKAY; 774 } 775 776 /** frees knapsack constraint data */ 777 static 778 SCIP_RETCODE consdataFree( 779 SCIP* scip, /**< SCIP data structure */ 780 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */ 781 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */ 782 ) 783 { 784 assert(consdata != NULL); 785 assert(*consdata != NULL); 786 787 if( (*consdata)->row != NULL ) 788 { 789 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) ); 790 } 791 if( (*consdata)->nlrow != NULL ) 792 { 793 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) ); 794 } 795 if( (*consdata)->eventdata != NULL ) 796 { 797 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) ); 798 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize); 799 } 800 if( (*consdata)->negcliquepartition != NULL ) 801 { 802 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize); 803 } 804 if( (*consdata)->cliquepartition != NULL ) 805 { 806 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize); 807 } 808 if( (*consdata)->vars != NULL ) 809 { 810 int v; 811 812 /* release variables */ 813 for( v = 0; v < (*consdata)->nvars; v++ ) 814 { 815 assert((*consdata)->vars[v] != NULL); 816 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) ); 817 } 818 819 assert( (*consdata)->weights != NULL ); 820 assert( (*consdata)->varssize > 0 ); 821 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize); 822 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize); 823 } 824 825 SCIPfreeBlockMemory(scip, consdata); 826 827 return SCIP_OKAY; 828 } 829 830 /** changes a single weight in knapsack constraint data */ 831 static 832 void consdataChgWeight( 833 SCIP_CONSDATA* consdata, /**< knapsack constraint data */ 834 int item, /**< item number */ 835 SCIP_Longint newweight /**< new weight of item */ 836 ) 837 { 838 SCIP_Longint oldweight; 839 SCIP_Longint weightdiff; 840 841 assert(consdata != NULL); 842 assert(0 <= item && item < consdata->nvars); 843 844 oldweight = consdata->weights[item]; 845 weightdiff = newweight - oldweight; 846 consdata->weights[item] = newweight; 847 848 /* update weight sums for all and fixed variables */ 849 updateWeightSums(consdata, consdata->vars[item], weightdiff); 850 851 if( consdata->eventdata != NULL ) 852 { 853 assert(consdata->eventdata[item] != NULL); 854 assert(consdata->eventdata[item]->weight == oldweight); 855 consdata->eventdata[item]->weight = newweight; 856 } 857 858 consdata->presolvedtiming = 0; 859 consdata->sorted = FALSE; 860 861 /* recalculate cliques extraction after a weight was increased */ 862 if( oldweight < newweight ) 863 { 864 consdata->cliquesadded = FALSE; 865 } 866 } 867 868 /** creates LP row corresponding to knapsack constraint */ 869 static 870 SCIP_RETCODE createRelaxation( 871 SCIP* scip, /**< SCIP data structure */ 872 SCIP_CONS* cons /**< knapsack constraint */ 873 ) 874 { 875 SCIP_CONSDATA* consdata; 876 int i; 877 878 consdata = SCIPconsGetData(cons); 879 assert(consdata != NULL); 880 assert(consdata->row == NULL); 881 882 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons), 883 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, 884 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsRemovable(cons)) ); 885 886 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) ); 887 for( i = 0; i < consdata->nvars; ++i ) 888 { 889 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) ); 890 } 891 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) ); 892 893 return SCIP_OKAY; 894 } 895 896 /** adds linear relaxation of knapsack constraint to the LP */ 897 static 898 SCIP_RETCODE addRelaxation( 899 SCIP* scip, /**< SCIP data structure */ 900 SCIP_CONS* cons, /**< knapsack constraint */ 901 SCIP_Bool* cutoff /**< whether a cutoff has been detected */ 902 ) 903 { 904 SCIP_CONSDATA* consdata; 905 906 assert( cutoff != NULL ); 907 *cutoff = FALSE; 908 909 consdata = SCIPconsGetData(cons); 910 assert(consdata != NULL); 911 912 if( consdata->row == NULL ) 913 { 914 SCIP_CALL( createRelaxation(scip, cons) ); 915 } 916 assert(consdata->row != NULL); 917 918 /* insert LP row as cut */ 919 if( !SCIProwIsInLP(consdata->row) ) 920 { 921 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ", 922 SCIPconsGetName(cons), consdata->capacity); 923 SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) ); 924 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) ); 925 } 926 927 return SCIP_OKAY; 928 } 929 930 /** adds knapsack constraint as row to the NLP, if not added yet */ 931 static 932 SCIP_RETCODE addNlrow( 933 SCIP* scip, /**< SCIP data structure */ 934 SCIP_CONS* cons /**< knapsack constraint */ 935 ) 936 { 937 SCIP_CONSDATA* consdata; 938 939 assert(SCIPisNLPConstructed(scip)); 940 941 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */ 942 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) ) 943 return SCIP_OKAY; 944 945 consdata = SCIPconsGetData(cons); 946 assert(consdata != NULL); 947 948 if( consdata->nlrow == NULL ) 949 { 950 SCIP_Real* coefs; 951 int i; 952 953 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) ); 954 for( i = 0; i < consdata->nvars; ++i ) 955 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/ 956 957 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0, 958 consdata->nvars, consdata->vars, coefs, NULL, 959 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) ); 960 961 assert(consdata->nlrow != NULL); 962 963 SCIPfreeBufferArray(scip, &coefs); 964 } 965 966 if( !SCIPnlrowIsInNLP(consdata->nlrow) ) 967 { 968 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) ); 969 } 970 971 return SCIP_OKAY; 972 } 973 974 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */ 975 static 976 SCIP_RETCODE checkCons( 977 SCIP* scip, /**< SCIP data structure */ 978 SCIP_CONS* cons, /**< constraint to check */ 979 SCIP_SOL* sol, /**< solution to check, NULL for current solution */ 980 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */ 981 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */ 982 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */ 983 ) 984 { 985 SCIP_CONSDATA* consdata; 986 987 assert(violated != NULL); 988 989 consdata = SCIPconsGetData(cons); 990 assert(consdata != NULL); 991 992 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n", 993 SCIPconsGetName(cons), (void*)sol, checklprows); 994 995 *violated = FALSE; 996 997 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) ) 998 { 999 SCIP_Real sum; 1000 SCIP_Longint integralsum; 1001 SCIP_Bool ishuge; 1002 SCIP_Real absviol; 1003 SCIP_Real relviol; 1004 int v; 1005 1006 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in 1007 * enforcement 1008 */ 1009 if( sol == NULL ) 1010 { 1011 SCIP_CALL( SCIPincConsAge(scip, cons) ); 1012 } 1013 1014 sum = 0.0; 1015 integralsum = 0; 1016 /* we perform a more exact comparison if the capacity does not exceed the huge value */ 1017 if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) ) 1018 { 1019 ishuge = TRUE; 1020 1021 /* sum over all weight times the corresponding solution value */ 1022 for( v = consdata->nvars - 1; v >= 0; --v ) 1023 { 1024 assert(SCIPvarIsBinary(consdata->vars[v])); 1025 sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]); 1026 } 1027 } 1028 else 1029 { 1030 ishuge = FALSE; 1031 1032 /* sum over all weight for which the variable has a solution value of 1 in feastol */ 1033 for( v = consdata->nvars - 1; v >= 0; --v ) 1034 { 1035 assert(SCIPvarIsBinary(consdata->vars[v])); 1036 1037 if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 ) 1038 integralsum += consdata->weights[v]; 1039 } 1040 } 1041 1042 /* calculate constraint violation and update it in solution */ 1043 absviol = ishuge ? sum : (SCIP_Real)integralsum; 1044 absviol -= consdata->capacity; 1045 relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity); 1046 if( sol != NULL ) 1047 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol); 1048 1049 if( SCIPisFeasPositive(scip, absviol) ) 1050 { 1051 *violated = TRUE; 1052 1053 /* only reset constraint age if we are in enforcement */ 1054 if( sol == NULL ) 1055 { 1056 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 1057 } 1058 1059 if( printreason ) 1060 { 1061 SCIP_CALL( SCIPprintCons(scip, cons, NULL) ); 1062 1063 SCIPinfoMessage(scip, NULL, ";\n"); 1064 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol); 1065 } 1066 } 1067 } 1068 1069 return SCIP_OKAY; 1070 } 1071 1072 /* IDX computes the integer index for the optimal solution array */ 1073 #define IDX(j,d) ((j)*(intcap)+(d)) 1074 1075 /** solves knapsack problem in maximization form exactly using dynamic programming; 1076 * if needed, one can provide arrays to store all selected items and all not selected items 1077 * 1078 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well 1079 * 1080 * @note the algorithm will first compute a greedy solution and terminate 1081 * if the greedy solution is proven to be optimal. 1082 * The dynamic programming algorithm runs with a time and space complexity 1083 * of O(nitems * capacity). 1084 * 1085 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space. 1086 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains 1087 * to be checked whether they are faster and whether they can reconstruct the solution. 1088 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method. 1089 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing. 1090 * This could be implemented, however, it would be technically a bit cumbersome, 1091 * since one needs the greedy solution and the LP-value for this. 1092 * This is currently only available after the redundant items have already been sorted out. 1093 */ 1094 SCIP_RETCODE SCIPsolveKnapsackExactly( 1095 SCIP* scip, /**< SCIP data structure */ 1096 int nitems, /**< number of available items */ 1097 SCIP_Longint* weights, /**< item weights */ 1098 SCIP_Real* profits, /**< item profits */ 1099 SCIP_Longint capacity, /**< capacity of knapsack */ 1100 int* items, /**< item numbers */ 1101 int* solitems, /**< array to store items in solution, or NULL */ 1102 int* nonsolitems, /**< array to store items not in solution, or NULL */ 1103 int* nsolitems, /**< pointer to store number of items in solution, or NULL */ 1104 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */ 1105 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */ 1106 SCIP_Bool* success /**< pointer to store if an error occured during solving 1107 * (normally a memory problem) */ 1108 ) 1109 { 1110 SCIP_RETCODE retcode; 1111 SCIP_Real* tempsort; 1112 SCIP_Real* optvalues; 1113 int intcap; 1114 int d; 1115 int j; 1116 int greedymedianpos; 1117 SCIP_Longint weightsum; 1118 int* myitems; 1119 SCIP_Longint* myweights; 1120 SCIP_Real* realweights; 1121 int* allcurrminweight; 1122 SCIP_Real* myprofits; 1123 int nmyitems; 1124 SCIP_Longint gcd; 1125 SCIP_Longint minweight; 1126 SCIP_Longint maxweight; 1127 int currminweight; 1128 SCIP_Longint greedysolweight; 1129 SCIP_Real greedysolvalue; 1130 SCIP_Real greedyupperbound; 1131 SCIP_Bool eqweights; 1132 SCIP_Bool intprofits; 1133 1134 assert(weights != NULL); 1135 assert(profits != NULL); 1136 assert(capacity >= 0); 1137 assert(items != NULL); 1138 assert(nitems >= 0); 1139 assert(success != NULL); 1140 1141 *success = TRUE; 1142 1143 #ifndef NDEBUG 1144 for( j = nitems - 1; j >= 0; --j ) 1145 assert(weights[j] >= 0); 1146 #endif 1147 1148 SCIPdebugMsg(scip, "Solving knapsack exactly.\n"); 1149 1150 /* initializing solution value */ 1151 if( solval != NULL ) 1152 *solval = 0.0; 1153 1154 /* init solution information */ 1155 if( solitems != NULL ) 1156 { 1157 assert(items != NULL); 1158 assert(nsolitems != NULL); 1159 assert(nonsolitems != NULL); 1160 assert(nnonsolitems != NULL); 1161 1162 *nnonsolitems = 0; 1163 *nsolitems = 0; 1164 } 1165 1166 /* allocate temporary memory */ 1167 SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) ); 1168 SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) ); 1169 SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) ); 1170 nmyitems = 0; 1171 weightsum = 0; 1172 minweight = SCIP_LONGINT_MAX; 1173 maxweight = 0; 1174 1175 /* remove unnecessary items */ 1176 for( j = 0; j < nitems; ++j ) 1177 { 1178 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX); 1179 1180 /* item does not fit */ 1181 if( weights[j] > capacity ) 1182 { 1183 if( solitems != NULL ) 1184 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/ 1185 } 1186 /* item is not profitable */ 1187 else if( profits[j] <= 0.0 ) 1188 { 1189 if( solitems != NULL ) 1190 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/ 1191 } 1192 /* item always fits */ 1193 else if( weights[j] == 0 ) 1194 { 1195 if( solitems != NULL ) 1196 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/ 1197 1198 if( solval != NULL ) 1199 *solval += profits[j]; 1200 } 1201 /* all important items */ 1202 else 1203 { 1204 myweights[nmyitems] = weights[j]; 1205 myprofits[nmyitems] = profits[j]; 1206 myitems[nmyitems] = items[j]; 1207 1208 /* remember smallest item */ 1209 if( myweights[nmyitems] < minweight ) 1210 minweight = myweights[nmyitems]; 1211 1212 /* remember bigest item */ 1213 if( myweights[nmyitems] > maxweight ) 1214 maxweight = myweights[nmyitems]; 1215 1216 weightsum += myweights[nmyitems]; 1217 ++nmyitems; 1218 } 1219 } 1220 1221 intprofits = TRUE; 1222 /* check if all profits are integer to strengthen the upper bound on the greedy solution */ 1223 for( j = 0; j < nmyitems && intprofits; ++j ) 1224 intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]); 1225 1226 /* if no item is left then goto end */ 1227 if( nmyitems == 0 ) 1228 { 1229 SCIPdebugMsg(scip, "After preprocessing no items are left.\n"); 1230 1231 goto TERMINATE; 1232 } 1233 1234 /* if all items fit, we also do not need to do the expensive stuff later on */ 1235 if( weightsum > 0 && weightsum <= capacity ) 1236 { 1237 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n"); 1238 1239 for( j = nmyitems - 1; j >= 0; --j ) 1240 { 1241 if( solitems != NULL ) 1242 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/ 1243 1244 if( solval != NULL ) 1245 *solval += myprofits[j]; 1246 } 1247 1248 goto TERMINATE; 1249 } 1250 1251 assert(0 < minweight && minweight <= capacity ); 1252 assert(0 < maxweight && maxweight <= capacity); 1253 1254 /* make weights relatively prime */ 1255 eqweights = TRUE; 1256 if( maxweight > 1 ) 1257 { 1258 /* determine greatest common divisor */ 1259 gcd = myweights[nmyitems - 1]; 1260 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j ) 1261 gcd = SCIPcalcGreComDiv(gcd, myweights[j]); 1262 1263 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd); 1264 1265 /* divide by greatest common divisor */ 1266 if( gcd > 1 ) 1267 { 1268 for( j = nmyitems - 1; j >= 0; --j ) 1269 { 1270 myweights[j] /= gcd; 1271 eqweights = eqweights && (myweights[j] == 1); 1272 } 1273 capacity /= gcd; 1274 minweight /= gcd; 1275 } 1276 else 1277 eqweights = FALSE; 1278 } 1279 assert(minweight <= capacity); 1280 1281 /* if only one item fits, then take the best */ 1282 if( minweight > capacity / 2 ) 1283 { 1284 int p; 1285 1286 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n"); 1287 1288 p = nmyitems - 1; 1289 1290 /* find best item */ 1291 for( j = nmyitems - 2; j >= 0; --j ) 1292 { 1293 if( myprofits[j] > myprofits[p] ) 1294 p = j; 1295 } 1296 1297 /* update solution information */ 1298 if( solitems != NULL ) 1299 { 1300 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL); 1301 1302 solitems[(*nsolitems)++] = myitems[p]; 1303 for( j = nmyitems - 1; j >= 0; --j ) 1304 { 1305 if( j != p ) 1306 nonsolitems[(*nnonsolitems)++] = myitems[j]; 1307 } 1308 } 1309 /* update solution value */ 1310 if( solval != NULL ) 1311 *solval += myprofits[p]; 1312 1313 goto TERMINATE; 1314 } 1315 1316 /* if all items have the same weight, then take the best */ 1317 if( eqweights ) 1318 { 1319 SCIP_Real addval = 0.0; 1320 1321 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n"); 1322 1323 SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems); 1324 1325 /* update solution information */ 1326 if( solitems != NULL || solval != NULL ) 1327 { 1328 SCIP_Longint i; 1329 1330 /* if all items would fit we had handled this case before */ 1331 assert((SCIP_Longint) nmyitems > capacity); 1332 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL); 1333 1334 /* take the first best items into the solution */ 1335 for( i = capacity - 1; i >= 0; --i ) 1336 { 1337 if( solitems != NULL ) 1338 solitems[(*nsolitems)++] = myitems[i]; 1339 addval += myprofits[i]; 1340 } 1341 1342 if( solitems != NULL ) 1343 { 1344 /* the rest are not in the solution */ 1345 for( i = nmyitems - 1; i >= capacity; --i ) 1346 nonsolitems[(*nnonsolitems)++] = myitems[i]; 1347 } 1348 } 1349 /* update solution value */ 1350 if( solval != NULL ) 1351 { 1352 assert(addval > 0.0); 1353 *solval += addval; 1354 } 1355 1356 goto TERMINATE; 1357 } 1358 1359 SCIPdebugMsg(scip, "Determine greedy solution.\n"); 1360 1361 /* sort myitems (plus corresponding arrays myweights and myprofits) such that 1362 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution 1363 */ 1364 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) ); 1365 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) ); 1366 1367 for( j = 0; j < nmyitems; ++j ) 1368 { 1369 tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]); 1370 realweights[j] = (SCIP_Real)myweights[j]; 1371 } 1372 1373 SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights, 1374 (SCIP_Real)capacity, nmyitems, &greedymedianpos); 1375 1376 SCIPfreeBufferArray(scip, &realweights); 1377 SCIPfreeBufferArray(scip, &tempsort); 1378 1379 /* initialize values for greedy solution information */ 1380 greedysolweight = 0; 1381 greedysolvalue = 0.0; 1382 1383 /* determine greedy solution */ 1384 for( j = 0; j < greedymedianpos; ++j ) 1385 { 1386 assert(myweights[j] <= capacity); 1387 1388 /* update greedy solution weight and value */ 1389 greedysolweight += myweights[j]; 1390 greedysolvalue += myprofits[j]; 1391 } 1392 1393 assert(0 < greedysolweight && greedysolweight <= capacity); 1394 assert(greedysolvalue > 0.0); 1395 1396 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if: 1397 * - the greedy solution reaches the capacity, because then the LP solution is integral; 1398 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */ 1399 greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]); 1400 if( intprofits ) 1401 greedyupperbound = SCIPfloor(scip, greedyupperbound); 1402 if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) ) 1403 { 1404 SCIPdebugMsg(scip, "Greedy solution is optimal.\n"); 1405 1406 /* update solution information */ 1407 if( solitems != NULL ) 1408 { 1409 int l; 1410 1411 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL); 1412 1413 /* collect items */ 1414 for( l = 0; l < j; ++l ) 1415 solitems[(*nsolitems)++] = myitems[l]; 1416 for ( ; l < nmyitems; ++l ) 1417 nonsolitems[(*nnonsolitems)++] = myitems[l]; 1418 } 1419 /* update solution value */ 1420 if( solval != NULL ) 1421 { 1422 assert(greedysolvalue > 0.0); 1423 *solval += greedysolvalue; 1424 } 1425 1426 goto TERMINATE; 1427 } 1428 1429 /* in the following table we do not need the first minweight columns */ 1430 capacity -= (minweight - 1); 1431 1432 /* we can only handle integers */ 1433 if( capacity >= INT_MAX ) 1434 { 1435 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n"); 1436 1437 *success = FALSE; 1438 goto TERMINATE; 1439 } 1440 assert(capacity < INT_MAX); 1441 1442 intcap = (int)capacity; 1443 assert(intcap >= 0); 1444 assert(nmyitems > 0); 1445 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */ 1446 1447 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while 1448 * computing the size for the allocation 1449 */ 1450 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*/ 1451 { 1452 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/ 1453 1454 *success = FALSE; 1455 goto TERMINATE; 1456 } 1457 1458 /* allocate temporary memory and check for memory exceedance */ 1459 retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap); 1460 if( retcode == SCIP_NOMEMORY ) 1461 { 1462 SCIPdebugMsg(scip, "Did not get enough memory.\n"); 1463 1464 *success = FALSE; 1465 goto TERMINATE; 1466 } 1467 else 1468 { 1469 SCIP_CALL( retcode ); 1470 } 1471 1472 SCIPdebugMsg(scip, "Start real exact algorithm.\n"); 1473 1474 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid; 1475 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is 1476 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing 1477 * 'nmyitem' values 1478 */ 1479 SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) ); 1480 assert(myweights[0] - minweight < INT_MAX); 1481 currminweight = (int) (myweights[0] - minweight); 1482 allcurrminweight[0] = currminweight; 1483 1484 /* fills first row of dynamic programming table with optimal values */ 1485 for( d = currminweight; d < intcap; ++d ) 1486 optvalues[d] = myprofits[0]; 1487 1488 /* fills dynamic programming table with optimal values */ 1489 for( j = 1; j < nmyitems; ++j ) 1490 { 1491 int intweight; 1492 1493 /* compute important part of weight, which will be represented in the table */ 1494 intweight = (int)(myweights[j] - minweight); 1495 assert(0 <= intweight && intweight < intcap); 1496 1497 /* copy all nonzeros from row above */ 1498 for( d = currminweight; d < intweight && d < intcap; ++d ) 1499 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)]; 1500 1501 /* update corresponding row */ 1502 for( d = intweight; d < intcap; ++d ) 1503 { 1504 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */ 1505 if( d < currminweight ) 1506 optvalues[IDX(j,d)] = myprofits[j]; 1507 else 1508 { 1509 SCIP_Real sumprofit; 1510 1511 if( d - myweights[j] < currminweight ) 1512 sumprofit = myprofits[j]; 1513 else 1514 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j]; 1515 1516 optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]); 1517 } 1518 } 1519 1520 /* update currminweight */ 1521 if( intweight < currminweight ) 1522 currminweight = intweight; 1523 1524 allcurrminweight[j] = currminweight; 1525 } 1526 1527 /* update optimal solution by following the table */ 1528 if( solitems != NULL ) 1529 { 1530 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL); 1531 d = intcap - 1; 1532 1533 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n"); 1534 1535 /* insert all items in (non-) solution vector */ 1536 for( j = nmyitems - 1; j > 0; --j ) 1537 { 1538 /* if the following condition holds this means all remaining items does not fit anymore */ 1539 if( d < allcurrminweight[j] ) 1540 { 1541 /* we cannot have exceeded our capacity */ 1542 assert((SCIP_Longint) d >= -minweight); 1543 break; 1544 } 1545 1546 /* collect solution items; the first condition means that no further item can fit anymore, but this does */ 1547 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] ) 1548 { 1549 solitems[(*nsolitems)++] = myitems[j]; 1550 1551 /* check that we do not have an underflow */ 1552 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d)); 1553 d = (int)(d - myweights[j]); 1554 } 1555 /* collect non-solution items */ 1556 else 1557 nonsolitems[(*nnonsolitems)++] = myitems[j]; 1558 } 1559 1560 /* insert remaining items */ 1561 if( d >= allcurrminweight[j] ) 1562 { 1563 assert(j == 0); 1564 solitems[(*nsolitems)++] = myitems[j]; 1565 } 1566 else 1567 { 1568 assert(j >= 0); 1569 assert(d < allcurrminweight[j]); 1570 1571 for( ; j >= 0; --j ) 1572 nonsolitems[(*nnonsolitems)++] = myitems[j]; 1573 } 1574 1575 assert(*nsolitems + *nnonsolitems == nitems); 1576 } 1577 1578 /* update solution value */ 1579 if( solval != NULL ) 1580 *solval += optvalues[IDX(nmyitems-1,intcap-1)]; 1581 SCIPfreeBufferArray(scip, &allcurrminweight); 1582 1583 /* free all temporary memory */ 1584 SCIPfreeBufferArray(scip, &optvalues); 1585 1586 TERMINATE: 1587 SCIPfreeBufferArray(scip, &myitems); 1588 SCIPfreeBufferArray(scip, &myprofits); 1589 SCIPfreeBufferArray(scip, &myweights); 1590 1591 return SCIP_OKAY; 1592 } 1593 1594 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's 1595 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not 1596 * selected items 1597 */ 1598 SCIP_RETCODE SCIPsolveKnapsackApproximately( 1599 SCIP* scip, /**< SCIP data structure */ 1600 int nitems, /**< number of available items */ 1601 SCIP_Longint* weights, /**< item weights */ 1602 SCIP_Real* profits, /**< item profits */ 1603 SCIP_Longint capacity, /**< capacity of knapsack */ 1604 int* items, /**< item numbers */ 1605 int* solitems, /**< array to store items in solution, or NULL */ 1606 int* nonsolitems, /**< array to store items not in solution, or NULL */ 1607 int* nsolitems, /**< pointer to store number of items in solution, or NULL */ 1608 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */ 1609 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */ 1610 ) 1611 { 1612 SCIP_Real* tempsort; 1613 SCIP_Longint solitemsweight; 1614 SCIP_Real* realweights; 1615 int j; 1616 int criticalindex; 1617 1618 assert(weights != NULL); 1619 assert(profits != NULL); 1620 assert(capacity >= 0); 1621 assert(items != NULL); 1622 assert(nitems >= 0); 1623 1624 if( solitems != NULL ) 1625 { 1626 *nsolitems = 0; 1627 *nnonsolitems = 0; 1628 } 1629 if( solval != NULL ) 1630 *solval = 0.0; 1631 1632 /* initialize data for median search */ 1633 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) ); 1634 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) ); 1635 for( j = nitems - 1; j >= 0; --j ) 1636 { 1637 tempsort[j] = profits[j]/((SCIP_Real) weights[j]); 1638 realweights[j] = (SCIP_Real)weights[j]; 1639 } 1640 1641 /* partially sort indices such that all elements that are larger than the break item appear first */ 1642 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex); 1643 1644 /* selects items as long as they fit into the knapsack */ 1645 solitemsweight = 0; 1646 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j ) 1647 { 1648 if( solitems != NULL ) 1649 solitems[(*nsolitems)++] = items[j]; 1650 1651 if( solval != NULL ) 1652 (*solval) += profits[j]; 1653 solitemsweight += weights[j]; 1654 } 1655 if ( solitems != NULL ) 1656 { 1657 for( ; j < nitems; j++ ) 1658 nonsolitems[(*nnonsolitems)++] = items[j]; 1659 } 1660 1661 SCIPfreeBufferArray(scip, &realweights); 1662 SCIPfreeBufferArray(scip, &tempsort); 1663 1664 return SCIP_OKAY; 1665 } 1666 1667 #ifdef SCIP_DEBUG 1668 /** prints all nontrivial GUB constraints and their LP solution values */ 1669 static 1670 void GUBsetPrint( 1671 SCIP* scip, /**< SCIP data structure */ 1672 SCIP_GUBSET* gubset, /**< GUB set data structure */ 1673 SCIP_VAR** vars, /**< variables in knapsack constraint */ 1674 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */ 1675 ) 1676 { 1677 int nnontrivialgubconss; 1678 int c; 1679 1680 nnontrivialgubconss = 0; 1681 1682 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n"); 1683 1684 /* print out all nontrivial GUB constraints, i.e., with more than one variable */ 1685 for( c = 0; c < gubset->ngubconss; c++ ) 1686 { 1687 SCIP_Real gubsolval; 1688 1689 assert(gubset->gubconss[c]->ngubvars >= 0); 1690 1691 /* nontrivial GUB */ 1692 if( gubset->gubconss[c]->ngubvars > 1 ) 1693 { 1694 int v; 1695 1696 gubsolval = 0.0; 1697 SCIPdebugMsg(scip, " GUB<%d>:\n", c); 1698 1699 /* print GUB var */ 1700 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ ) 1701 { 1702 int currentvar; 1703 1704 currentvar = gubset->gubconss[c]->gubvars[v]; 1705 if( solvals != NULL ) 1706 { 1707 gubsolval += solvals[currentvar]; 1708 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]); 1709 } 1710 else 1711 { 1712 SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar])); 1713 } 1714 } 1715 1716 /* check whether LP solution satisfies the GUB constraint */ 1717 if( solvals != NULL ) 1718 { 1719 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval, 1720 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : ""); 1721 } 1722 else 1723 { 1724 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : ""); 1725 } 1726 nnontrivialgubconss++; 1727 } 1728 } 1729 1730 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss); 1731 } 1732 #endif 1733 1734 /** creates an empty GUB constraint */ 1735 static 1736 SCIP_RETCODE GUBconsCreate( 1737 SCIP* scip, /**< SCIP data structure */ 1738 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */ 1739 ) 1740 { 1741 assert(scip != NULL); 1742 assert(gubcons != NULL); 1743 1744 /* allocate memory for GUB constraint data structures */ 1745 SCIP_CALL( SCIPallocBuffer(scip, gubcons) ); 1746 (*gubcons)->gubvarssize = GUBCONSGROWVALUE; 1747 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) ); 1748 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) ); 1749 1750 (*gubcons)->ngubvars = 0; 1751 1752 return SCIP_OKAY; 1753 } 1754 1755 /** frees GUB constraint */ 1756 static 1757 void GUBconsFree( 1758 SCIP* scip, /**< SCIP data structure */ 1759 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */ 1760 ) 1761 { 1762 assert(scip != NULL); 1763 assert(gubcons != NULL); 1764 assert((*gubcons)->gubvars != NULL); 1765 assert((*gubcons)->gubvarsstatus != NULL); 1766 1767 /* free allocated memory */ 1768 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus); 1769 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars); 1770 SCIPfreeBuffer(scip, gubcons); 1771 } 1772 1773 /** adds variable to given GUB constraint */ 1774 static 1775 SCIP_RETCODE GUBconsAddVar( 1776 SCIP* scip, /**< SCIP data structure */ 1777 SCIP_GUBCONS* gubcons, /**< GUB constraint data */ 1778 int var /**< index of given variable in knapsack constraint */ 1779 ) 1780 { 1781 assert(scip != NULL); 1782 assert(gubcons != NULL); 1783 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize); 1784 assert(gubcons->gubvars != NULL); 1785 assert(gubcons->gubvarsstatus != NULL); 1786 assert(var >= 0); 1787 1788 /* add variable to GUB constraint */ 1789 gubcons->gubvars[gubcons->ngubvars] = var; 1790 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL; 1791 gubcons->ngubvars++; 1792 1793 /* increase space allocated to GUB constraint if the number of variables reaches the size */ 1794 if( gubcons->ngubvars == gubcons->gubvarssize ) 1795 { 1796 int newlen; 1797 1798 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE; 1799 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) ); 1800 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) ); 1801 1802 gubcons->gubvarssize = newlen; 1803 } 1804 1805 return SCIP_OKAY; 1806 } 1807 1808 /** deletes variable from its current GUB constraint */ 1809 static 1810 SCIP_RETCODE GUBconsDelVar( 1811 SCIP* scip, /**< SCIP data structure */ 1812 SCIP_GUBCONS* gubcons, /**< GUB constraint data */ 1813 int var, /**< index of given variable in knapsack constraint */ 1814 int gubvarsidx /**< index of the variable in its current GUB constraint */ 1815 ) 1816 { 1817 assert(scip != NULL); 1818 assert(gubcons != NULL); 1819 assert(var >= 0); 1820 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars); 1821 assert(gubcons->ngubvars >= gubvarsidx+1); 1822 assert(gubcons->gubvars[gubvarsidx] == var); 1823 1824 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */ 1825 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1]; 1826 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1]; 1827 gubcons->ngubvars--; 1828 1829 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */ 1830 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 ) 1831 { 1832 int newlen; 1833 1834 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE; 1835 1836 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) ); 1837 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) ); 1838 1839 gubcons->gubvarssize = newlen; 1840 } 1841 1842 return SCIP_OKAY; 1843 } 1844 1845 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */ 1846 static 1847 SCIP_RETCODE GUBsetMoveVar( 1848 SCIP* scip, /**< SCIP data structure */ 1849 SCIP_GUBSET* gubset, /**< GUB set data structure */ 1850 SCIP_VAR** vars, /**< variables in knapsack constraint */ 1851 int var, /**< index of given variable in knapsack constraint */ 1852 int oldgubcons, /**< index of old GUB constraint of given variable */ 1853 int newgubcons /**< index of new GUB constraint of given variable */ 1854 ) 1855 { 1856 int oldgubvaridx; 1857 int replacevar; 1858 int j; 1859 1860 assert(scip != NULL); 1861 assert(gubset != NULL); 1862 assert(var >= 0); 1863 assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss); 1864 assert(newgubcons >= 0 && newgubcons < gubset->ngubconss); 1865 assert(oldgubcons != newgubcons); 1866 assert(gubset->gubconssidx[var] == oldgubcons); 1867 assert(gubset->gubconss[oldgubcons]->ngubvars > 0); 1868 assert(gubset->gubconss[newgubcons]->ngubvars >= 0); 1869 1870 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons); 1871 1872 oldgubvaridx = gubset->gubvarsidx[var]; 1873 1874 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */ 1875 SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) ); 1876 1877 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement; 1878 * replacement variable is given by old position of the deleted variable 1879 */ 1880 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx]; 1881 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars); 1882 gubset->gubvarsidx[replacevar] = oldgubvaridx; 1883 1884 /* add variable to the end of new GUB constraint */ 1885 SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) ); 1886 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var); 1887 1888 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */ 1889 gubset->gubconssidx[var] = newgubcons; 1890 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1; 1891 1892 /* delete old GUB constraint if it became empty */ 1893 if( gubset->gubconss[oldgubcons]->ngubvars == 0 ) 1894 { 1895 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons); 1896 #ifdef SCIP_DEBUG 1897 GUBsetPrint(scip, gubset, vars, NULL); 1898 #endif 1899 1900 /* free old GUB constraint */ 1901 GUBconsFree(scip, &gubset->gubconss[oldgubcons]); 1902 1903 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */ 1904 if( oldgubcons != gubset->ngubconss-1 ) 1905 { 1906 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1]; 1907 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1]; 1908 1909 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement; 1910 * replacement GUB is given by old position of the deleted GUB 1911 */ 1912 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ ) 1913 { 1914 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1); 1915 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons; 1916 } 1917 } 1918 1919 /* update number of GUB constraints */ 1920 gubset->ngubconss--; 1921 1922 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint 1923 * (because it was at the end of the GUB constraint array) 1924 */ 1925 assert(gubset->gubconssidx[var] == newgubcons 1926 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons)); 1927 } 1928 #ifndef NDEBUG 1929 else 1930 assert(gubset->gubconssidx[var] == newgubcons); 1931 #endif 1932 1933 return SCIP_OKAY; 1934 } 1935 1936 /** swaps two variables in the same GUB constraint */ 1937 static 1938 void GUBsetSwapVars( 1939 SCIP* scip, /**< SCIP data structure */ 1940 SCIP_GUBSET* gubset, /**< GUB set data structure */ 1941 int var1, /**< first variable to be swapped */ 1942 int var2 /**< second variable to be swapped */ 1943 ) 1944 { 1945 int gubcons; 1946 int var1idx; 1947 GUBVARSTATUS var1status; 1948 int var2idx; 1949 GUBVARSTATUS var2status; 1950 1951 assert(scip != NULL); 1952 assert(gubset != NULL); 1953 1954 gubcons = gubset->gubconssidx[var1]; 1955 assert(gubcons == gubset->gubconssidx[var2]); 1956 1957 /* nothing to be done if both variables are the same */ 1958 if( var1 == var2 ) 1959 return; 1960 1961 /* swap index and status of variables in GUB constraint */ 1962 var1idx = gubset->gubvarsidx[var1]; 1963 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx]; 1964 var2idx = gubset->gubvarsidx[var2]; 1965 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx]; 1966 1967 gubset->gubvarsidx[var1] = var2idx; 1968 gubset->gubconss[gubcons]->gubvars[var1idx] = var2; 1969 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status; 1970 1971 gubset->gubvarsidx[var2] = var1idx; 1972 gubset->gubconss[gubcons]->gubvars[var2idx] = var1; 1973 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status; 1974 } 1975 1976 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */ 1977 static 1978 SCIP_RETCODE GUBsetCreate( 1979 SCIP* scip, /**< SCIP data structure */ 1980 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */ 1981 int nvars, /**< number of variables in the knapsack constraint */ 1982 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 1983 SCIP_Longint capacity /**< capacity of knapsack */ 1984 ) 1985 { 1986 int i; 1987 1988 assert(scip != NULL); 1989 assert(gubset != NULL); 1990 assert(nvars > 0); 1991 assert(weights != NULL); 1992 assert(capacity >= 0); 1993 1994 /* allocate memory for GUB set data structures */ 1995 SCIP_CALL( SCIPallocBuffer(scip, gubset) ); 1996 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) ); 1997 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) ); 1998 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) ); 1999 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) ); 2000 (*gubset)->ngubconss = nvars; 2001 (*gubset)->nvars = nvars; 2002 2003 /* initialize the set of GUB constraints */ 2004 for( i = 0; i < nvars; i++ ) 2005 { 2006 /* assign each variable to a new (trivial) GUB constraint */ 2007 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) ); 2008 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) ); 2009 2010 /* set status of GUB constraint to initial */ 2011 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL; 2012 2013 (*gubset)->gubconssidx[i] = i; 2014 (*gubset)->gubvarsidx[i] = 0; 2015 assert((*gubset)->gubconss[i]->ngubvars == 1); 2016 2017 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */ 2018 if( weights[i] > capacity ) 2019 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED; 2020 } 2021 2022 return SCIP_OKAY; 2023 } 2024 2025 /** frees GUB set data structure */ 2026 static 2027 void GUBsetFree( 2028 SCIP* scip, /**< SCIP data structure */ 2029 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */ 2030 ) 2031 { 2032 int i; 2033 2034 assert(scip != NULL); 2035 assert(gubset != NULL); 2036 assert((*gubset)->gubconss != NULL); 2037 assert((*gubset)->gubconsstatus != NULL); 2038 assert((*gubset)->gubconssidx != NULL); 2039 assert((*gubset)->gubvarsidx != NULL); 2040 2041 /* free all GUB constraints */ 2042 for( i = (*gubset)->ngubconss-1; i >= 0; --i ) 2043 { 2044 assert((*gubset)->gubconss[i] != NULL); 2045 GUBconsFree(scip, &(*gubset)->gubconss[i]); 2046 } 2047 2048 /* free allocated memory */ 2049 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx ); 2050 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx ); 2051 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus ); 2052 SCIPfreeBufferArray( scip, &(*gubset)->gubconss ); 2053 SCIPfreeBuffer(scip, gubset); 2054 } 2055 2056 #ifndef NDEBUG 2057 /** checks whether GUB set data structure is consistent */ 2058 static 2059 SCIP_RETCODE GUBsetCheck( 2060 SCIP* scip, /**< SCIP data structure */ 2061 SCIP_GUBSET* gubset, /**< GUB set data structure */ 2062 SCIP_VAR** vars /**< variables in the knapsack constraint */ 2063 ) 2064 { 2065 int i; 2066 int gubconsidx; 2067 int gubvaridx; 2068 SCIP_VAR* var1; 2069 SCIP_VAR* var2; 2070 SCIP_Bool var1negated; 2071 SCIP_Bool var2negated; 2072 2073 assert(scip != NULL); 2074 assert(gubset != NULL); 2075 2076 SCIPdebugMsg(scip, " GUB set consistency check:\n"); 2077 2078 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */ 2079 for( i = 0; i < gubset->nvars; i++ ) 2080 { 2081 gubconsidx = gubset->gubconssidx[i]; 2082 gubvaridx = gubset->gubvarsidx[i]; 2083 2084 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i ) 2085 { 2086 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i, 2087 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] ); 2088 } 2089 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i); 2090 } 2091 2092 /* checks for each GUB whether all pairs of its variables have a common clique */ 2093 for( i = 0; i < gubset->ngubconss; i++ ) 2094 { 2095 int j; 2096 2097 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ ) 2098 { 2099 int k; 2100 2101 /* get corresponding active problem variable */ 2102 var1 = vars[gubset->gubconss[i]->gubvars[j]]; 2103 var1negated = FALSE; 2104 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) ); 2105 2106 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ ) 2107 { 2108 /* get corresponding active problem variable */ 2109 var2 = vars[gubset->gubconss[i]->gubvars[k]]; 2110 var2negated = FALSE; 2111 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) ); 2112 2113 if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) ) 2114 { 2115 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j, 2116 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k, 2117 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]])); 2118 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j, 2119 SCIPvarGetName(var1), k, 2120 SCIPvarGetName(var2)); 2121 } 2122 2123 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */ 2124 assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE)); 2125 } 2126 } 2127 } 2128 SCIPdebugMsg(scip, " --> successful\n"); 2129 2130 return SCIP_OKAY; 2131 } 2132 #endif 2133 2134 /** calculates a partition of the given set of binary variables into cliques; 2135 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they 2136 * were assigned to the same clique; 2137 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of 2138 * the preceding variables was assigned to clique i-1; 2139 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one 2140 * variable) and for the remaining variables, a partition with a small number of cliques is constructed 2141 */ 2142 2143 static 2144 SCIP_RETCODE GUBsetCalcCliquePartition( 2145 SCIP*const scip, /**< SCIP data structure */ 2146 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */ 2147 int const nvars, /**< number of variables in the clique */ 2148 int*const cliquepartition, /**< array of length nvars to store the clique partition */ 2149 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */ 2150 SCIP_Real* solvals /**< solution values of all given binary variables */ 2151 ) 2152 { 2153 SCIP_VAR** tmpvars; 2154 SCIP_VAR** cliquevars; 2155 SCIP_Bool* cliquevalues; 2156 SCIP_Bool* tmpvalues; 2157 int* varseq; 2158 int* sortkeys; 2159 int ncliquevars; 2160 int maxncliquevarscomp; 2161 int nignorevars; 2162 int nvarsused; 2163 int i; 2164 2165 assert(scip != NULL); 2166 assert(nvars == 0 || vars != NULL); 2167 assert(nvars == 0 || cliquepartition != NULL); 2168 assert(ncliques != NULL); 2169 2170 if( nvars == 0 ) 2171 { 2172 *ncliques = 0; 2173 return SCIP_OKAY; 2174 } 2175 2176 /* allocate temporary memory for storing the variables of the current clique */ 2177 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) ); 2178 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) ); 2179 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) ); 2180 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) ); 2181 SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) ); 2182 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) ); 2183 2184 /* initialize the cliquepartition array with -1 */ 2185 /* initialize the tmpvalues array */ 2186 for( i = nvars - 1; i >= 0; --i ) 2187 { 2188 tmpvalues[i] = TRUE; 2189 cliquepartition[i] = -1; 2190 } 2191 2192 /* get corresponding active problem variables */ 2193 SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) ); 2194 2195 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables 2196 * by nondecreasing number of cliques the variables are in 2197 */ 2198 nignorevars = 0; 2199 nvarsused = 0; 2200 for( i = 0; i < nvars; i++ ) 2201 { 2202 if( SCIPisFeasEQ(scip, solvals[i], 1.0) ) 2203 { 2204 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */ 2205 varseq[nvars-1-nignorevars] = i; 2206 nignorevars++; 2207 } 2208 else 2209 { 2210 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */ 2211 varseq[nvarsused] = i; 2212 sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]); 2213 nvarsused++; 2214 } 2215 } 2216 assert(nvarsused + nignorevars == nvars); 2217 2218 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */ 2219 SCIPsortIntInt(sortkeys, varseq, nvarsused); 2220 2221 maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP); 2222 2223 /* calculate the clique partition */ 2224 *ncliques = 0; 2225 for( i = 0; i < nvars; ++i ) 2226 { 2227 if( cliquepartition[varseq[i]] == -1 ) 2228 { 2229 int j; 2230 2231 /* variable starts a new clique */ 2232 cliquepartition[varseq[i]] = *ncliques; 2233 cliquevars[0] = tmpvars[varseq[i]]; 2234 cliquevalues[0] = tmpvalues[varseq[i]]; 2235 ncliquevars = 1; 2236 2237 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and 2238 * if the variable has LP value 1 we do not want it to be in nontrivial cliques 2239 */ 2240 if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused ) 2241 { 2242 /* greedily fill up the clique */ 2243 for( j = i + 1; j < nvarsused; ++j ) 2244 { 2245 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */ 2246 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) ) 2247 { 2248 int k; 2249 2250 /* check if every variable in the actual clique is in clique with the new variable */ 2251 for( k = ncliquevars - 1; k >= 0; --k ) 2252 { 2253 if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k], 2254 cliquevalues[k], TRUE) ) 2255 break; 2256 } 2257 2258 if( k == -1 ) 2259 { 2260 /* put the variable into the same clique */ 2261 cliquepartition[varseq[j]] = cliquepartition[varseq[i]]; 2262 cliquevars[ncliquevars] = tmpvars[varseq[j]]; 2263 cliquevalues[ncliquevars] = tmpvalues[varseq[j]]; 2264 ++ncliquevars; 2265 } 2266 } 2267 } 2268 } 2269 2270 /* this clique is finished */ 2271 ++(*ncliques); 2272 } 2273 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1); 2274 2275 /* break if we reached the maximal number of comparisons */ 2276 if( i * nvars > maxncliquevarscomp ) 2277 break; 2278 } 2279 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */ 2280 for( ; i < nvars; ++i ) 2281 { 2282 if( cliquepartition[varseq[i]] == -1 ) 2283 { 2284 cliquepartition[varseq[i]] = *ncliques; 2285 ++(*ncliques); 2286 } 2287 } 2288 2289 /* free temporary memory */ 2290 SCIPfreeBufferArray(scip, &sortkeys); 2291 SCIPfreeBufferArray(scip, &varseq); 2292 SCIPfreeBufferArray(scip, &tmpvars); 2293 SCIPfreeBufferArray(scip, &tmpvalues); 2294 SCIPfreeBufferArray(scip, &cliquevalues); 2295 SCIPfreeBufferArray(scip, &cliquevars); 2296 2297 return SCIP_OKAY; 2298 } 2299 2300 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */ 2301 static 2302 SCIP_RETCODE GUBsetGetCliquePartition( 2303 SCIP* scip, /**< SCIP data structure */ 2304 SCIP_GUBSET* gubset, /**< GUB set data structure */ 2305 SCIP_VAR** vars, /**< variables in the knapsack constraint */ 2306 SCIP_Real* solvals /**< solution values of all knapsack variables */ 2307 ) 2308 { 2309 int* cliquepartition; 2310 int* gubfirstvar; 2311 int ncliques; 2312 int currentgubconsidx; 2313 int newgubconsidx; 2314 int cliqueidx; 2315 int nvars; 2316 int i; 2317 2318 assert(scip != NULL); 2319 assert(gubset != NULL); 2320 assert(vars != NULL); 2321 2322 nvars = gubset->nvars; 2323 assert(nvars >= 0); 2324 2325 /* allocate temporary memory for clique partition */ 2326 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) ); 2327 2328 /* compute sophisticated clique partition */ 2329 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) ); 2330 2331 /* allocate temporary memory for GUB set data structure */ 2332 SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) ); 2333 2334 /* translate GUB partition into GUB set data structure */ 2335 for( i = 0; i < ncliques; i++ ) 2336 { 2337 /* initialize first variable for every GUB */ 2338 gubfirstvar[i] = -1; 2339 } 2340 /* move every knapsack variable into GUB defined by clique partition */ 2341 for( i = 0; i < nvars; i++ ) 2342 { 2343 assert(cliquepartition[i] >= 0); 2344 2345 cliqueidx = cliquepartition[i]; 2346 currentgubconsidx = gubset->gubconssidx[i]; 2347 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 ); 2348 2349 /* variable is first element in GUB constraint defined by clique partition */ 2350 if( gubfirstvar[cliqueidx] == -1 ) 2351 { 2352 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB); 2353 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar() 2354 */ 2355 assert(gubset->gubvarsidx[i] == 0); 2356 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i); 2357 2358 /* remember the first variable found for the current GUB */ 2359 gubfirstvar[cliqueidx] = i; 2360 } 2361 /* variable is additional element of GUB constraint defined by clique partition */ 2362 else 2363 { 2364 assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i); 2365 2366 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the 2367 * first variable of this GUB constraint 2368 */ 2369 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]]; 2370 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */ 2371 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) ); 2372 2373 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i); 2374 } 2375 } 2376 2377 #ifdef SCIP_DEBUG 2378 /* prints GUB set data structure */ 2379 GUBsetPrint(scip, gubset, vars, solvals); 2380 #endif 2381 2382 #ifndef NDEBUG 2383 /* checks consistency of GUB set data structure */ 2384 SCIP_CALL( GUBsetCheck(scip, gubset, vars) ); 2385 #endif 2386 2387 /* free temporary memory */ 2388 SCIPfreeBufferArray(scip, &gubfirstvar); 2389 SCIPfreeBufferArray(scip, &cliquepartition); 2390 2391 return SCIP_OKAY; 2392 } 2393 2394 /** 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$ 2395 * 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 2396 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists. 2397 */ 2398 static 2399 SCIP_RETCODE getCover( 2400 SCIP* scip, /**< SCIP data structure */ 2401 SCIP_VAR** vars, /**< variables in knapsack constraint */ 2402 int nvars, /**< number of variables in knapsack constraint */ 2403 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 2404 SCIP_Longint capacity, /**< capacity of knapsack */ 2405 SCIP_Real* solvals, /**< solution values of all problem variables */ 2406 int* covervars, /**< pointer to store cover variables */ 2407 int* noncovervars, /**< pointer to store noncover variables */ 2408 int* ncovervars, /**< pointer to store number of cover variables */ 2409 int* nnoncovervars, /**< pointer to store number of noncover variables */ 2410 SCIP_Longint* coverweight, /**< pointer to store weight of cover */ 2411 SCIP_Bool* found, /**< pointer to store whether a cover was found */ 2412 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */ 2413 int* ntightened, /**< pointer to store number of variables with tightened upper bound */ 2414 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */ 2415 ) 2416 { 2417 SCIP_Longint* transweights; 2418 SCIP_Real* transprofits; 2419 SCIP_Longint transcapacity; 2420 SCIP_Longint fixedonesweight; 2421 SCIP_Longint itemsweight; 2422 SCIP_Bool infeasible; 2423 int* fixedones; 2424 int* fixedzeros; 2425 int* items; 2426 int nfixedones; 2427 int nfixedzeros; 2428 int nitems; 2429 int j; 2430 2431 assert(scip != NULL); 2432 assert(vars != NULL); 2433 assert(nvars > 0); 2434 assert(weights != NULL); 2435 assert(capacity >= 0); 2436 assert(solvals != NULL); 2437 assert(covervars != NULL); 2438 assert(noncovervars != NULL); 2439 assert(ncovervars != NULL); 2440 assert(nnoncovervars != NULL); 2441 assert(coverweight != NULL); 2442 assert(found != NULL); 2443 assert(ntightened != NULL); 2444 assert(fractional != NULL); 2445 2446 SCIPdebugMsg(scip, " get cover for knapsack constraint\n"); 2447 2448 /* allocates temporary memory */ 2449 SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) ); 2450 SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) ); 2451 SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) ); 2452 SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) ); 2453 SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) ); 2454 2455 *found = FALSE; 2456 *ncovervars = 0; 2457 *nnoncovervars = 0; 2458 *coverweight = 0; 2459 *fractional = TRUE; 2460 2461 /* gets the following sets 2462 * N_1 = {j in N : x*_j = 1} (fixedones), 2463 * N_0 = {j in N : x*_j = 0} (fixedzeros) and 2464 * N\(N_0 & N_1) (items), 2465 * where x*_j is the solution value of variable x_j 2466 */ 2467 nfixedones = 0; 2468 nfixedzeros = 0; 2469 nitems = 0; 2470 fixedonesweight = 0; 2471 itemsweight = 0; 2472 *ntightened = 0; 2473 for( j = 0; j < nvars; j++ ) 2474 { 2475 assert(SCIPvarIsBinary(vars[j])); 2476 2477 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */ 2478 if( weights[j] > capacity ) 2479 { 2480 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) ); 2481 assert(!infeasible); 2482 (*ntightened)++; 2483 continue; 2484 } 2485 2486 /* variable x_j has solution value one */ 2487 if( SCIPisFeasEQ(scip, solvals[j], 1.0) ) 2488 { 2489 fixedones[nfixedones] = j; 2490 nfixedones++; 2491 fixedonesweight += weights[j]; 2492 } 2493 /* variable x_j has solution value zero */ 2494 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) ) 2495 { 2496 fixedzeros[nfixedzeros] = j; 2497 nfixedzeros++; 2498 } 2499 /* variable x_j has fractional solution value */ 2500 else 2501 { 2502 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) ); 2503 items[nitems] = j; 2504 nitems++; 2505 itemsweight += weights[j]; 2506 } 2507 } 2508 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened)); 2509 2510 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop 2511 * the separation routine 2512 */ 2513 assert(nitems >= 0); 2514 if( nitems == 0 ) 2515 { 2516 *fractional = FALSE; 2517 goto TERMINATE; 2518 } 2519 assert(*fractional); 2520 2521 /* transforms the traditional separation problem (under consideration of the following fixing: 2522 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0) 2523 * 2524 * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j 2525 * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j 2526 * z_j in {0,1}, j in N\(N_0 & N_1) 2527 * 2528 * to a knapsack problem in maximization form by complementing the variables 2529 * 2530 * sum_{j in N\(N_0 & N_1)} (1 - x*_j) - 2531 * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j 2532 * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1) 2533 * z_j in {0,1}, j in N\(N_0 & N_1) 2534 */ 2535 2536 /* gets weight and profit of variables in transformed knapsack problem */ 2537 for( j = 0; j < nitems; j++ ) 2538 { 2539 transweights[j] = weights[items[j]]; 2540 transprofits[j] = 1.0 - solvals[items[j]]; 2541 } 2542 /* gets capacity of transformed knapsack problem */ 2543 transcapacity = fixedonesweight + itemsweight - capacity - 1; 2544 2545 /* if capacity of transformed knapsack problem is less than zero, there is no cover 2546 * (when variables fixed to zero are not used) 2547 */ 2548 if( transcapacity < 0 ) 2549 { 2550 assert(!(*found)); 2551 goto TERMINATE; 2552 } 2553 2554 if( modtransused ) 2555 { 2556 /* transforms the modified separation problem (under consideration of the following fixing: 2557 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0) 2558 * 2559 * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j 2560 * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j 2561 * z_j in {0,1}, j in N\(N_0 & N_1) 2562 * 2563 * to a knapsack problem in maximization form by complementing the variables 2564 * 2565 * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j - 2566 * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j 2567 * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1) 2568 * z_j in {0,1}, j in N\(N_0 & N_1) 2569 */ 2570 2571 /* gets weight and profit of variables in modified transformed knapsack problem */ 2572 for( j = 0; j < nitems; j++ ) 2573 { 2574 transprofits[j] *= weights[items[j]]; 2575 assert(SCIPisFeasPositive(scip, transprofits[j])); 2576 } 2577 } 2578 2579 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified) 2580 * transformed knapsack problem using Dantzig's method and rounding down the solution. 2581 * let z* be the solution, then 2582 * j in C, if z*_j = 0 and 2583 * i in N\C, if z*_j = 1. 2584 */ 2585 SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items, 2586 noncovervars, covervars, nnoncovervars, ncovervars, NULL) ); 2587 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/ 2588 2589 /* constructs cover C (sum_{j in C} a_j > a_0) */ 2590 for( j = 0; j < *ncovervars; j++ ) 2591 { 2592 (*coverweight) += weights[covervars[j]]; 2593 } 2594 2595 /* adds all variables from N_1 to C */ 2596 for( j = 0; j < nfixedones; j++ ) 2597 { 2598 covervars[*ncovervars] = fixedones[j]; 2599 (*ncovervars)++; 2600 (*coverweight) += weights[fixedones[j]]; 2601 } 2602 2603 /* adds all variables from N_0 to N\C */ 2604 for( j = 0; j < nfixedzeros; j++ ) 2605 { 2606 noncovervars[*nnoncovervars] = fixedzeros[j]; 2607 (*nnoncovervars)++; 2608 } 2609 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened)); 2610 assert((*coverweight) > capacity); 2611 *found = TRUE; 2612 2613 TERMINATE: 2614 /* frees temporary memory */ 2615 SCIPfreeBufferArray(scip, &items); 2616 SCIPfreeBufferArray(scip, &fixedzeros); 2617 SCIPfreeBufferArray(scip, &fixedones); 2618 SCIPfreeBufferArray(scip, &transprofits); 2619 SCIPfreeBufferArray(scip, &transweights); 2620 2621 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n"); 2622 2623 return SCIP_OKAY; 2624 } 2625 2626 #ifndef NDEBUG 2627 /** checks if minweightidx is set correctly 2628 */ 2629 static 2630 SCIP_Bool checkMinweightidx( 2631 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 2632 SCIP_Longint capacity, /**< capacity of knapsack */ 2633 int* covervars, /**< pointer to store cover variables */ 2634 int ncovervars, /**< pointer to store number of cover variables */ 2635 SCIP_Longint coverweight, /**< pointer to store weight of cover */ 2636 int minweightidx, /**< index of variable in cover variables with minimum weight */ 2637 int j /**< current index in cover variables */ 2638 ) 2639 { 2640 SCIP_Longint minweight; 2641 int i; 2642 2643 assert(weights != NULL); 2644 assert(covervars != NULL); 2645 assert(ncovervars > 0); 2646 2647 minweight = weights[covervars[minweightidx]]; 2648 2649 /* checks if all cover variables before index j have weight greater than minweight */ 2650 for( i = 0; i < j; i++ ) 2651 { 2652 assert(weights[covervars[i]] > minweight); 2653 if( weights[covervars[i]] <= minweight ) 2654 return FALSE; 2655 } 2656 2657 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */ 2658 for( i = 0; i < j; i++ ) 2659 { 2660 assert(coverweight - weights[covervars[i]] <= capacity); 2661 if( coverweight - weights[covervars[i]] > capacity ) 2662 return FALSE; 2663 } 2664 return TRUE; 2665 } 2666 #endif 2667 2668 2669 /** 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$, 2670 * 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$ 2671 */ 2672 static 2673 void getPartitionCovervars( 2674 SCIP* scip, /**< SCIP data structure */ 2675 SCIP_Real* solvals, /**< solution values of all problem variables */ 2676 int* covervars, /**< cover variables */ 2677 int ncovervars, /**< number of cover variables */ 2678 int* varsC1, /**< pointer to store variables in C1 */ 2679 int* varsC2, /**< pointer to store variables in C2 */ 2680 int* nvarsC1, /**< pointer to store number of variables in C1 */ 2681 int* nvarsC2 /**< pointer to store number of variables in C2 */ 2682 ) 2683 { 2684 int j; 2685 2686 assert(scip != NULL); 2687 assert(ncovervars >= 0); 2688 assert(solvals != NULL); 2689 assert(covervars != NULL); 2690 assert(varsC1 != NULL); 2691 assert(varsC2 != NULL); 2692 assert(nvarsC1 != NULL); 2693 assert(nvarsC2 != NULL); 2694 2695 *nvarsC1 = 0; 2696 *nvarsC2 = 0; 2697 for( j = 0; j < ncovervars; j++ ) 2698 { 2699 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0)); 2700 2701 /* variable has solution value one */ 2702 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) ) 2703 { 2704 varsC2[*nvarsC2] = covervars[j]; 2705 (*nvarsC2)++; 2706 } 2707 /* variable has solution value less than one */ 2708 else 2709 { 2710 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0)); 2711 varsC1[*nvarsC1] = covervars[j]; 2712 (*nvarsC1)++; 2713 } 2714 } 2715 assert((*nvarsC1) + (*nvarsC2) == ncovervars); 2716 } 2717 2718 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from 2719 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively. 2720 */ 2721 static 2722 SCIP_RETCODE changePartitionCovervars( 2723 SCIP* scip, /**< SCIP data structure */ 2724 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 2725 int* varsC1, /**< pointer to store variables in C1 */ 2726 int* varsC2, /**< pointer to store variables in C2 */ 2727 int* nvarsC1, /**< pointer to store number of variables in C1 */ 2728 int* nvarsC2 /**< pointer to store number of variables in C2 */ 2729 ) 2730 { 2731 SCIP_Real* sortkeysC2; 2732 int j; 2733 2734 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1); 2735 assert(*nvarsC2 > 0); 2736 2737 /* allocates temporary memory */ 2738 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) ); 2739 2740 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */ 2741 for( j = 0; j < *nvarsC2; j++ ) 2742 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]]; 2743 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2); 2744 2745 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */ 2746 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]); 2747 while( *nvarsC1 < 2 && *nvarsC2 > 0 ) 2748 { 2749 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1]; 2750 (*nvarsC1)++; 2751 (*nvarsC2)--; 2752 } 2753 2754 /* frees temporary memory */ 2755 SCIPfreeBufferArray(scip, &sortkeysC2); 2756 2757 return SCIP_OKAY; 2758 } 2759 2760 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */ 2761 static 2762 SCIP_RETCODE changePartitionFeasiblesetvars( 2763 SCIP* scip, /**< SCIP data structure */ 2764 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 2765 int* varsC1, /**< pointer to store variables in C1 */ 2766 int* varsC2, /**< pointer to store variables in C2 */ 2767 int* nvarsC1, /**< pointer to store number of variables in C1 */ 2768 int* nvarsC2 /**< pointer to store number of variables in C2 */ 2769 ) 2770 { 2771 SCIP_Real* sortkeysC2; 2772 int j; 2773 2774 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1); 2775 assert(*nvarsC2 > 0); 2776 2777 /* allocates temporary memory */ 2778 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) ); 2779 2780 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */ 2781 for( j = 0; j < *nvarsC2; j++ ) 2782 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]]; 2783 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2); 2784 2785 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */ 2786 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]); 2787 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1]; 2788 (*nvarsC1)++; 2789 (*nvarsC2)--; 2790 2791 /* frees temporary memory */ 2792 SCIPfreeBufferArray(scip, &sortkeysC2); 2793 2794 return SCIP_OKAY; 2795 } 2796 2797 2798 /** 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$ 2799 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and 2800 * \f$F = (N \setminus C) \setminus F\f$ 2801 */ 2802 static 2803 void getPartitionNoncovervars( 2804 SCIP* scip, /**< SCIP data structure */ 2805 SCIP_Real* solvals, /**< solution values of all problem variables */ 2806 int* noncovervars, /**< noncover variables */ 2807 int nnoncovervars, /**< number of noncover variables */ 2808 int* varsF, /**< pointer to store variables in F */ 2809 int* varsR, /**< pointer to store variables in R */ 2810 int* nvarsF, /**< pointer to store number of variables in F */ 2811 int* nvarsR /**< pointer to store number of variables in R */ 2812 ) 2813 { 2814 int j; 2815 2816 assert(scip != NULL); 2817 assert(nnoncovervars >= 0); 2818 assert(solvals != NULL); 2819 assert(noncovervars != NULL); 2820 assert(varsF != NULL); 2821 assert(varsR != NULL); 2822 assert(nvarsF != NULL); 2823 assert(nvarsR != NULL); 2824 2825 *nvarsF = 0; 2826 *nvarsR = 0; 2827 2828 for( j = 0; j < nnoncovervars; j++ ) 2829 { 2830 /* variable has solution value zero */ 2831 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) ) 2832 { 2833 varsR[*nvarsR] = noncovervars[j]; 2834 (*nvarsR)++; 2835 } 2836 /* variable has solution value greater than zero */ 2837 else 2838 { 2839 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0)); 2840 varsF[*nvarsF] = noncovervars[j]; 2841 (*nvarsF)++; 2842 } 2843 } 2844 assert((*nvarsF) + (*nvarsR) == nnoncovervars); 2845 } 2846 2847 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential 2848 * lifting procedure 2849 */ 2850 static 2851 SCIP_RETCODE getLiftingSequence( 2852 SCIP* scip, /**< SCIP data structure */ 2853 SCIP_Real* solvals, /**< solution values of all problem variables */ 2854 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 2855 int* varsF, /**< pointer to store variables in F */ 2856 int* varsC2, /**< pointer to store variables in C2 */ 2857 int* varsR, /**< pointer to store variables in R */ 2858 int nvarsF, /**< number of variables in F */ 2859 int nvarsC2, /**< number of variables in C2 */ 2860 int nvarsR /**< number of variables in R */ 2861 ) 2862 { 2863 SORTKEYPAIR** sortkeypairsF; 2864 SORTKEYPAIR* sortkeypairsFstore; 2865 SCIP_Real* sortkeysC2; 2866 SCIP_Real* sortkeysR; 2867 int j; 2868 2869 assert(scip != NULL); 2870 assert(solvals != NULL); 2871 assert(weights != NULL); 2872 assert(varsF != NULL); 2873 assert(varsC2 != NULL); 2874 assert(varsR != NULL); 2875 assert(nvarsF >= 0); 2876 assert(nvarsC2 >= 0); 2877 assert(nvarsR >= 0); 2878 2879 /* allocates temporary memory */ 2880 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) ); 2881 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) ); 2882 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) ); 2883 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) ); 2884 2885 /* gets sorting key for variables in F corresponding to the following lifting sequence 2886 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e. 2887 * x*_1 >= x*_2 >= ... >= x*_|F| 2888 * in case of equality uses 2889 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2| 2890 */ 2891 for( j = 0; j < nvarsF; j++ ) 2892 { 2893 sortkeypairsF[j] = &(sortkeypairsFstore[j]); 2894 sortkeypairsF[j]->key1 = solvals[varsF[j]]; 2895 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]]; 2896 } 2897 2898 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence 2899 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2| 2900 */ 2901 for( j = 0; j < nvarsC2; j++ ) 2902 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]]; 2903 2904 /* gets sorting key for variables in R corresponding to the following lifting sequence 2905 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R| 2906 */ 2907 for( j = 0; j < nvarsR; j++ ) 2908 sortkeysR[j] = (SCIP_Real) weights[varsR[j]]; 2909 2910 /* sorts F, C2 and R */ 2911 if( nvarsF > 0 ) 2912 { 2913 SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF); 2914 } 2915 if( nvarsC2 > 0 ) 2916 { 2917 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2); 2918 } 2919 if( nvarsR > 0) 2920 { 2921 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR); 2922 } 2923 2924 /* frees temporary memory */ 2925 SCIPfreeBufferArray(scip, &sortkeysR); 2926 SCIPfreeBufferArray(scip, &sortkeysC2); 2927 SCIPfreeBufferArray(scip, &sortkeypairsFstore); 2928 SCIPfreeBufferArray(scip, &sortkeypairsF); 2929 2930 return SCIP_OKAY; 2931 } 2932 2933 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs 2934 * for the sequential GUB wise lifting procedure 2935 */ 2936 static 2937 SCIP_RETCODE getLiftingSequenceGUB( 2938 SCIP* scip, /**< SCIP data structure */ 2939 SCIP_GUBSET* gubset, /**< GUB set data structure */ 2940 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */ 2941 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 2942 int* varsC1, /**< variables in C1 */ 2943 int* varsC2, /**< variables in C2 */ 2944 int* varsF, /**< variables in F */ 2945 int* varsR, /**< variables in R */ 2946 int nvarsC1, /**< number of variables in C1 */ 2947 int nvarsC2, /**< number of variables in C2 */ 2948 int nvarsF, /**< number of variables in F */ 2949 int nvarsR, /**< number of variables in R */ 2950 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */ 2951 int* gubconsGC2, /**< pointer to store GUBs in GC2 */ 2952 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */ 2953 int* gubconsGR, /**< pointer to store GUBs in GR */ 2954 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */ 2955 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */ 2956 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */ 2957 int* ngubconsGR, /**< pointer to store number of GUBs in GR */ 2958 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */ 2959 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */ 2960 ) 2961 { 2962 SORTKEYPAIR** sortkeypairsGFC1; 2963 SORTKEYPAIR* sortkeypairsGFC1store; 2964 SCIP_Real* sortkeysC1; 2965 SCIP_Real* sortkeysC2; 2966 SCIP_Real* sortkeysR; 2967 int* nC1varsingubcons; 2968 int var; 2969 int gubconsidx; 2970 int varidx; 2971 int ngubconss; 2972 int ngubconsGOC1; 2973 int targetvar; 2974 #ifndef NDEBUG 2975 int nvarsprocessed = 0; 2976 #endif 2977 int i; 2978 int j; 2979 2980 #if GUBSPLITGNC1GUBS 2981 SCIP_Bool gubconswithF; 2982 int origngubconss; 2983 origngubconss = gubset->ngubconss; 2984 #endif 2985 2986 assert(scip != NULL); 2987 assert(gubset != NULL); 2988 assert(solvals != NULL); 2989 assert(weights != NULL); 2990 assert(varsC1 != NULL); 2991 assert(varsC2 != NULL); 2992 assert(varsF != NULL); 2993 assert(varsR != NULL); 2994 assert(nvarsC1 > 0); 2995 assert(nvarsC2 >= 0); 2996 assert(nvarsF >= 0); 2997 assert(nvarsR >= 0); 2998 assert(gubconsGC1 != NULL); 2999 assert(gubconsGC2 != NULL); 3000 assert(gubconsGFC1 != NULL); 3001 assert(gubconsGR != NULL); 3002 assert(ngubconsGC1 != NULL); 3003 assert(ngubconsGC2 != NULL); 3004 assert(ngubconsGFC1 != NULL); 3005 assert(ngubconsGR != NULL); 3006 assert(maxgubvarssize != NULL); 3007 3008 ngubconss = gubset->ngubconss; 3009 ngubconsGOC1 = 0; 3010 3011 /* GUBs are categorized into different types according to the variables in volved 3012 * - GOC1: involves variables in C1 only -- no C2, R, F 3013 * - GNC1: involves variables in C1 and F (and R) -- no C2 3014 * - GF: involves variables in F (and R) only -- no C1, C2 3015 * - GC2: involves variables in C2 only -- no C1, R, F 3016 * - GR: involves variables in R only -- no C1, C2, F 3017 * which requires splitting GUBs in case they include variable in F and R. 3018 * 3019 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence. 3020 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR. 3021 * - second ordering level is 3022 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality 3023 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1 3024 * GR: non-increasing max{ a_k : k in GR_j} 3025 * 3026 * in additon, another GUB union, which is helpful for the lifting procedure, is formed 3027 * - GC1: GUBs of category GOC1 and GNC1 3028 * with second ordering level non-decreasing min{ a_k : k in GC1_j }; 3029 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB 3030 */ 3031 3032 /* allocates temporary memory */ 3033 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) ); 3034 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) ); 3035 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) ); 3036 3037 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R 3038 * - F: non-increasing x*_j and non-increasing a_j in case of equality 3039 * - C2: non-increasing a_j 3040 * - R: non-increasing a_j 3041 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j). 3042 */ 3043 3044 /* gets sorting key for variables in C1 corresponding to the following ordering 3045 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1| 3046 */ 3047 for( j = 0; j < nvarsC1; j++ ) 3048 { 3049 /* gets sortkeys */ 3050 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]]; 3051 3052 /* update status of variable in its gub constraint */ 3053 gubconsidx = gubset->gubconssidx[varsC1[j]]; 3054 varidx = gubset->gubvarsidx[varsC1[j]]; 3055 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1; 3056 } 3057 3058 /* gets sorting key for variables in F corresponding to the following ordering 3059 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and 3060 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality 3061 * and updates status of each variable in F in GUB set data structure 3062 */ 3063 for( j = 0; j < nvarsF; j++ ) 3064 { 3065 /* update status of variable in its gub constraint */ 3066 gubconsidx = gubset->gubconssidx[varsF[j]]; 3067 varidx = gubset->gubvarsidx[varsF[j]]; 3068 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F; 3069 } 3070 3071 /* gets sorting key for variables in C2 corresponding to the following ordering 3072 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2| 3073 * and updates status of each variable in F in GUB set data structure 3074 */ 3075 for( j = 0; j < nvarsC2; j++ ) 3076 { 3077 /* gets sortkeys */ 3078 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]]; 3079 3080 /* update status of variable in its gub constraint */ 3081 gubconsidx = gubset->gubconssidx[varsC2[j]]; 3082 varidx = gubset->gubvarsidx[varsC2[j]]; 3083 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2; 3084 } 3085 3086 /* gets sorting key for variables in R corresponding to the following ordering 3087 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R| 3088 * and updates status of each variable in F in GUB set data structure 3089 */ 3090 for( j = 0; j < nvarsR; j++ ) 3091 { 3092 /* gets sortkeys */ 3093 sortkeysR[j] = (SCIP_Real) weights[varsR[j]]; 3094 3095 /* update status of variable in its gub constraint */ 3096 gubconsidx = gubset->gubconssidx[varsR[j]]; 3097 varidx = gubset->gubvarsidx[varsR[j]]; 3098 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R; 3099 } 3100 3101 /* sorts C1, F, C2 and R */ 3102 assert(nvarsC1 > 0); 3103 SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1); 3104 3105 if( nvarsC2 > 0 ) 3106 { 3107 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2); 3108 } 3109 if( nvarsR > 0) 3110 { 3111 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR); 3112 } 3113 3114 /* frees temporary memory */ 3115 SCIPfreeBufferArray(scip, &sortkeysR); 3116 SCIPfreeBufferArray(scip, &sortkeysC2); 3117 SCIPfreeBufferArray(scip, &sortkeysC1); 3118 3119 /* allocate and initialize temporary memory for sorting GUB constraints */ 3120 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) ); 3121 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) ); 3122 SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) ); 3123 BMSclearMemoryArray(nC1varsingubcons, ngubconss); 3124 for( i = 0; i < ngubconss; i++) 3125 { 3126 sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]); 3127 sortkeypairsGFC1[i]->key1 = 0.0; 3128 sortkeypairsGFC1[i]->key2 = 0.0; 3129 } 3130 *ngubconsGC1 = 0; 3131 *ngubconsGC2 = 0; 3132 *ngubconsGFC1 = 0; 3133 *ngubconsGR = 0; 3134 *ngubconscapexceed = 0; 3135 *maxgubvarssize = 0; 3136 3137 #ifndef NDEBUG 3138 for( i = 0; i < gubset->ngubconss; i++ ) 3139 assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL); 3140 #endif 3141 3142 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs 3143 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight). 3144 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering 3145 * non-increasing number of variables in F, and 3146 * non-increasing max{x*_k : k in GFC1_j} in case of equality 3147 */ 3148 for( i = 0; i < nvarsC1; i++ ) 3149 { 3150 int nvarsC1capexceed; 3151 3152 nvarsC1capexceed = 0; 3153 3154 var = varsC1[i]; 3155 gubconsidx = gubset->gubconssidx[var]; 3156 varidx = gubset->gubvarsidx[var]; 3157 3158 assert(gubconsidx >= 0 && gubconsidx < ngubconss); 3159 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1); 3160 3161 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth; 3162 * note that variables in C1 are already sorted by non-decreasing weigth 3163 */ 3164 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]]; 3165 GUBsetSwapVars(scip, gubset, var, targetvar); 3166 nC1varsingubcons[gubconsidx]++; 3167 3168 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */ 3169 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL ) 3170 { 3171 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1 3172 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1); 3173 continue; 3174 } 3175 3176 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into 3177 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1) 3178 */ 3179 #if GUBSPLITGNC1GUBS 3180 gubconswithF = FALSE; 3181 #endif 3182 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ ) 3183 { 3184 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2); 3185 3186 /* C1-variable: update number of C1/capacity exceeding variables */ 3187 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 ) 3188 { 3189 nvarsC1capexceed++; 3190 #ifndef NDEBUG 3191 nvarsprocessed++; 3192 #endif 3193 } 3194 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */ 3195 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F ) 3196 { 3197 #if GUBSPLITGNC1GUBS 3198 gubconswithF = TRUE; 3199 #endif 3200 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0; 3201 3202 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 ) 3203 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]]; 3204 } 3205 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED ) 3206 { 3207 nvarsC1capexceed++; 3208 } 3209 else 3210 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R); 3211 } 3212 3213 /* update set of GC1 GUBs */ 3214 gubconsGC1[*ngubconsGC1] = gubconsidx; 3215 (*ngubconsGC1)++; 3216 3217 /* update maximum size of all GUB constraints */ 3218 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize ) 3219 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize; 3220 3221 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */ 3222 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars ) 3223 { 3224 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1; 3225 ngubconsGOC1++; 3226 } 3227 else 3228 { 3229 #if GUBSPLITGNC1GUBS 3230 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */ 3231 if( !gubconswithF ) 3232 { 3233 GUBVARSTATUS movevarstatus; 3234 3235 assert(gubset->ngubconss < gubset->nvars); 3236 3237 /* create a new GUB for GR part of splitting */ 3238 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) ); 3239 gubset->ngubconss++; 3240 ngubconss = gubset->ngubconss; 3241 3242 /* fill GR with R variables in current GUB */ 3243 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- ) 3244 { 3245 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j]; 3246 if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 ) 3247 { 3248 assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED); 3249 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j], 3250 gubconsidx, ngubconss-1) ); 3251 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] = 3252 movevarstatus; 3253 } 3254 } 3255 3256 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1; 3257 ngubconsGOC1++; 3258 3259 gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR; 3260 gubconsGR[*ngubconsGR] = ngubconss-1; 3261 (*ngubconsGR)++; 3262 } 3263 /* variables in C1, F, and maybe R: GNC1 GUB */ 3264 else 3265 { 3266 assert(gubconswithF); 3267 3268 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1; 3269 gubconsGFC1[*ngubconsGFC1] = gubconsidx; 3270 (*ngubconsGFC1)++; 3271 } 3272 #else 3273 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1; 3274 gubconsGFC1[*ngubconsGFC1] = gubconsidx; 3275 (*ngubconsGFC1)++; 3276 #endif 3277 } 3278 } 3279 3280 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over) 3281 * are already sorted correctly 3282 */ 3283 for( i = 0; i < nvarsC2; i++ ) 3284 { 3285 var = varsC2[i]; 3286 gubconsidx = gubset->gubconssidx[var]; 3287 varidx = gubset->gubvarsidx[var]; 3288 3289 assert(gubconsidx >= 0 && gubconsidx < ngubconss); 3290 assert(gubset->gubconss[gubconsidx]->ngubvars == 1); 3291 assert(varidx == 0); 3292 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2); 3293 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL); 3294 3295 /* set status of GC2 GUB */ 3296 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2; 3297 3298 /* update group of GC2 GUBs */ 3299 gubconsGC2[*ngubconsGC2] = gubconsidx; 3300 (*ngubconsGC2)++; 3301 3302 /* update maximum size of all GUB constraints */ 3303 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize ) 3304 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize; 3305 3306 #ifndef NDEBUG 3307 nvarsprocessed++; 3308 #endif 3309 } 3310 3311 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering 3312 * non-increasing number of variables in F, and 3313 * non-increasing max{x*_k : k in GFC1_j} in case of equality 3314 */ 3315 for( i = 0; i < nvarsF; i++ ) 3316 { 3317 var = varsF[i]; 3318 gubconsidx = gubset->gubconssidx[var]; 3319 varidx = gubset->gubvarsidx[var]; 3320 3321 assert(gubconsidx >= 0 && gubconsidx < ngubconss); 3322 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F); 3323 3324 #ifndef NDEBUG 3325 nvarsprocessed++; 3326 #endif 3327 3328 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */ 3329 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL ) 3330 { 3331 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF 3332 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1); 3333 continue; 3334 } 3335 3336 /* set status of GF GUB */ 3337 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF; 3338 3339 /* update sorting key of corresponding GFC1 GUB */ 3340 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ ) 3341 { 3342 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2 3343 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1); 3344 3345 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */ 3346 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F ) 3347 { 3348 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0; 3349 3350 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 ) 3351 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]]; 3352 } 3353 } 3354 3355 /* update set of GFC1 GUBs */ 3356 gubconsGFC1[*ngubconsGFC1] = gubconsidx; 3357 (*ngubconsGFC1)++; 3358 3359 /* update maximum size of all GUB constraints */ 3360 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize ) 3361 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize; 3362 } 3363 3364 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted 3365 * correctly 3366 */ 3367 for( i = 0; i < nvarsR; i++ ) 3368 { 3369 var = varsR[i]; 3370 gubconsidx = gubset->gubconssidx[var]; 3371 varidx = gubset->gubvarsidx[var]; 3372 3373 assert(gubconsidx >= 0 && gubconsidx < ngubconss); 3374 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R); 3375 3376 #ifndef NDEBUG 3377 nvarsprocessed++; 3378 #endif 3379 3380 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */ 3381 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL ) 3382 { 3383 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR 3384 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF 3385 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1); 3386 continue; 3387 } 3388 3389 /* set status of GR GUB */ 3390 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR; 3391 3392 /* update set of GR GUBs */ 3393 gubconsGR[*ngubconsGR] = gubconsidx; 3394 (*ngubconsGR)++; 3395 3396 /* update maximum size of all GUB constraints */ 3397 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize ) 3398 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize; 3399 } 3400 assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR); 3401 3402 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */ 3403 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR)); 3404 assert(*ngubconscapexceed >= 0); 3405 #ifndef NDEBUG 3406 { 3407 int check; 3408 3409 check = 0; 3410 3411 /* remaining not handled GUBs should only contain capacity exceeding variables */ 3412 for( i = 0; i < ngubconss; i++ ) 3413 { 3414 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL ) 3415 check++; 3416 } 3417 assert(check == *ngubconscapexceed); 3418 } 3419 #endif 3420 3421 /* sort GFCI GUBs according to computed sorting keys */ 3422 if( (*ngubconsGFC1) > 0 ) 3423 { 3424 SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1)); 3425 } 3426 3427 /* free temporary memory */ 3428 #if GUBSPLITGNC1GUBS 3429 ngubconss = origngubconss; 3430 #endif 3431 SCIPfreeBufferArray(scip, &nC1varsingubcons); 3432 SCIPfreeBufferArray(scip, &sortkeypairsGFC1store); 3433 SCIPfreeBufferArray(scip, &sortkeypairsGFC1); 3434 3435 return SCIP_OKAY; 3436 } 3437 3438 /** enlarges minweight table to at least the given length */ 3439 static 3440 SCIP_RETCODE enlargeMinweights( 3441 SCIP* scip, /**< SCIP data structure */ 3442 SCIP_Longint** minweightsptr, /**< pointer to minweights table */ 3443 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */ 3444 int* minweightssize, /**< pointer to current size of minweights table */ 3445 int newlen /**< new length of minweights table */ 3446 ) 3447 { 3448 int j; 3449 3450 assert(minweightsptr != NULL); 3451 assert(*minweightsptr != NULL); 3452 assert(minweightslen != NULL); 3453 assert(*minweightslen >= 0); 3454 assert(minweightssize != NULL); 3455 assert(*minweightssize >= 0); 3456 3457 if( newlen > *minweightssize ) 3458 { 3459 int newsize; 3460 3461 /* reallocate table memory */ 3462 newsize = SCIPcalcMemGrowSize(scip, newlen); 3463 SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) ); 3464 *minweightssize = newsize; 3465 } 3466 assert(newlen <= *minweightssize); 3467 3468 /* initialize new elements */ 3469 for( j = *minweightslen; j < newlen; ++j ) 3470 (*minweightsptr)[j] = SCIP_LONGINT_MAX; 3471 *minweightslen = newlen; 3472 3473 return SCIP_OKAY; 3474 } 3475 3476 /** lifts given inequality 3477 * sum_{j in M_1} x_j <= alpha_0 3478 * valid for 3479 * 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 } 3480 * to a valid inequality 3481 * 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 3482 * <= alpha_0 + sum_{j in M_2} alpha_j 3483 * for 3484 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 }; 3485 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and 3486 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and 3487 * extended weight inequalities. 3488 */ 3489 static 3490 SCIP_RETCODE sequentialUpAndDownLifting( 3491 SCIP* scip, /**< SCIP data structure */ 3492 SCIP_VAR** vars, /**< variables in knapsack constraint */ 3493 int nvars, /**< number of variables in knapsack constraint */ 3494 int ntightened, /**< number of variables with tightened upper bound */ 3495 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 3496 SCIP_Longint capacity, /**< capacity of knapsack */ 3497 SCIP_Real* solvals, /**< solution values of all problem variables */ 3498 int* varsM1, /**< variables in M_1 */ 3499 int* varsM2, /**< variables in M_2 */ 3500 int* varsF, /**< variables in F */ 3501 int* varsR, /**< variables in R */ 3502 int nvarsM1, /**< number of variables in M_1 */ 3503 int nvarsM2, /**< number of variables in M_2 */ 3504 int nvarsF, /**< number of variables in F */ 3505 int nvarsR, /**< number of variables in R */ 3506 int alpha0, /**< rights hand side of given valid inequality */ 3507 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */ 3508 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */ 3509 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */ 3510 ) 3511 { 3512 SCIP_Longint* minweights; 3513 SCIP_Real* sortkeys; 3514 SCIP_Longint fixedonesweight; 3515 int minweightssize; 3516 int minweightslen; 3517 int j; 3518 int w; 3519 3520 assert(scip != NULL); 3521 assert(vars != NULL); 3522 assert(nvars >= 0); 3523 assert(weights != NULL); 3524 assert(capacity >= 0); 3525 assert(solvals != NULL); 3526 assert(varsM1 != NULL); 3527 assert(varsM2 != NULL); 3528 assert(varsF != NULL); 3529 assert(varsR != NULL); 3530 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened); 3531 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened); 3532 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened); 3533 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened); 3534 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened); 3535 assert(alpha0 >= 0); 3536 assert(liftcoefs != NULL); 3537 assert(cutact != NULL); 3538 assert(liftrhs != NULL); 3539 3540 /* allocates temporary memory */ 3541 minweightssize = nvarsM1 + 1; 3542 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) ); 3543 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) ); 3544 3545 /* initializes data structures */ 3546 BMSclearMemoryArray(liftcoefs, nvars); 3547 *cutact = 0.0; 3548 3549 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1| 3550 * and calculates activity of the current valid inequality 3551 */ 3552 for( j = 0; j < nvarsM1; j++ ) 3553 { 3554 assert(liftcoefs[varsM1[j]] == 0); 3555 liftcoefs[varsM1[j]] = 1; 3556 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]); 3557 (*cutact) += solvals[varsM1[j]]; 3558 } 3559 3560 SCIPsortRealInt(sortkeys, varsM1, nvarsM1); 3561 3562 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] = 3563 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k} 3564 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w 3565 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1}, 3566 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k}; 3567 */ 3568 minweights[0] = 0; 3569 for( w = 1; w <= nvarsM1; w++ ) 3570 minweights[w] = minweights[w-1] + weights[varsM1[w-1]]; 3571 minweightslen = nvarsM1 + 1; 3572 3573 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */ 3574 fixedonesweight = 0; 3575 for( j = 0; j < nvarsM2; j++ ) 3576 fixedonesweight += weights[varsM2[j]]; 3577 assert(fixedonesweight >= 0); 3578 3579 /* initializes right hand side of lifted valid inequality */ 3580 *liftrhs = alpha0; 3581 3582 /* sequentially up-lifts all variables in F: */ 3583 for( j = 0; j < nvarsF; j++ ) 3584 { 3585 SCIP_Longint weight; 3586 int liftvar; 3587 int liftcoef; 3588 int z; 3589 3590 liftvar = varsF[j]; 3591 weight = weights[liftvar]; 3592 assert(liftvar >= 0 && liftvar < nvars); 3593 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0)); 3594 assert(weight > 0); 3595 3596 /* knapsack problem is infeasible: 3597 * sets z = 0 3598 */ 3599 if( capacity - fixedonesweight - weight < 0 ) 3600 { 3601 z = 0; 3602 } 3603 /* knapsack problem is feasible: 3604 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs, 3605 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i} 3606 */ 3607 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight ) 3608 { 3609 z = *liftrhs; 3610 } 3611 /* knapsack problem is feasible: 3612 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } 3613 */ 3614 else 3615 { 3616 int left; 3617 int right; 3618 int middle; 3619 3620 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight); 3621 left = 0; 3622 right = (*liftrhs) + 1; 3623 while( left < right - 1 ) 3624 { 3625 middle = (left + right) / 2; 3626 assert(0 <= middle && middle < minweightslen); 3627 if( minweights[middle] <= capacity - fixedonesweight - weight ) 3628 left = middle; 3629 else 3630 right = middle; 3631 } 3632 assert(left == right - 1); 3633 assert(0 <= left && left < minweightslen); 3634 assert(minweights[left] <= capacity - fixedonesweight - weight ); 3635 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight); 3636 3637 /* now z = left */ 3638 z = left; 3639 assert(z <= *liftrhs); 3640 } 3641 3642 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */ 3643 liftcoef = (*liftrhs) - z; 3644 liftcoefs[liftvar] = liftcoef; 3645 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1); 3646 3647 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */ 3648 if( liftcoef == 0 ) 3649 continue; 3650 3651 /* updates activity of current valid inequality */ 3652 (*cutact) += liftcoef * solvals[liftvar]; 3653 3654 /* enlarges current minweight table: 3655 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries 3656 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries 3657 * and sets minweights_i[w] = infinity for 3658 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k} 3659 */ 3660 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) ); 3661 3662 /* updates minweight table: minweight_i+1[w] = 3663 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i 3664 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i 3665 */ 3666 for( w = minweightslen - 1; w >= 0; w-- ) 3667 { 3668 SCIP_Longint min; 3669 if( w < liftcoef ) 3670 { 3671 min = MIN(minweights[w], weight); 3672 minweights[w] = min; 3673 } 3674 else 3675 { 3676 assert(w >= liftcoef); 3677 min = MIN(minweights[w], minweights[w - liftcoef] + weight); 3678 minweights[w] = min; 3679 } 3680 } 3681 } 3682 assert(minweights[0] == 0); 3683 3684 /* sequentially down-lifts all variables in M_2: */ 3685 for( j = 0; j < nvarsM2; j++ ) 3686 { 3687 SCIP_Longint weight; 3688 int liftvar; 3689 int liftcoef; 3690 int left; 3691 int right; 3692 int middle; 3693 int z; 3694 3695 liftvar = varsM2[j]; 3696 weight = weights[liftvar]; 3697 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0)); 3698 assert(liftvar >= 0 && liftvar < nvars); 3699 assert(weight > 0); 3700 3701 /* uses binary search to find 3702 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}} 3703 */ 3704 left = 0; 3705 right = minweightslen; 3706 while( left < right - 1 ) 3707 { 3708 middle = (left + right) / 2; 3709 assert(0 <= middle && middle < minweightslen); 3710 if( minweights[middle] <= capacity - fixedonesweight + weight ) 3711 left = middle; 3712 else 3713 right = middle; 3714 } 3715 assert(left == right - 1); 3716 assert(0 <= left && left < minweightslen); 3717 assert(minweights[left] <= capacity - fixedonesweight + weight ); 3718 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight); 3719 3720 /* now z = left */ 3721 z = left; 3722 assert(z >= *liftrhs); 3723 3724 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */ 3725 liftcoef = z - (*liftrhs); 3726 liftcoefs[liftvar] = liftcoef; 3727 assert(liftcoef >= 0); 3728 3729 /* updates sum of weights of variables fixed to one */ 3730 fixedonesweight -= weight; 3731 3732 /* updates right-hand side of current valid inequality */ 3733 (*liftrhs) += liftcoef; 3734 assert(*liftrhs >= alpha0); 3735 3736 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */ 3737 if( liftcoef == 0 ) 3738 continue; 3739 3740 /* updates activity of current valid inequality */ 3741 (*cutact) += liftcoef * solvals[liftvar]; 3742 3743 /* enlarges current minweight table: 3744 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries 3745 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries 3746 * and sets minweights_i[w] = infinity for 3747 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k} 3748 */ 3749 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) ); 3750 3751 /* updates minweight table: minweight_i+1[w] = 3752 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i 3753 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i 3754 */ 3755 for( w = minweightslen - 1; w >= 0; w-- ) 3756 { 3757 SCIP_Longint min; 3758 if( w < liftcoef ) 3759 { 3760 min = MIN(minweights[w], weight); 3761 minweights[w] = min; 3762 } 3763 else 3764 { 3765 assert(w >= liftcoef); 3766 min = MIN(minweights[w], minweights[w - liftcoef] + weight); 3767 minweights[w] = min; 3768 } 3769 } 3770 } 3771 assert(fixedonesweight == 0); 3772 assert(*liftrhs >= alpha0); 3773 3774 /* sequentially up-lifts all variables in R: */ 3775 for( j = 0; j < nvarsR; j++ ) 3776 { 3777 SCIP_Longint weight; 3778 int liftvar; 3779 int liftcoef; 3780 int z; 3781 3782 liftvar = varsR[j]; 3783 weight = weights[liftvar]; 3784 assert(liftvar >= 0 && liftvar < nvars); 3785 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0)); 3786 assert(weight > 0); 3787 assert(capacity - weight >= 0); 3788 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight); 3789 3790 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs, 3791 * if minweights_i[liftrhs] <= a_0 - a_{j_i} 3792 */ 3793 if( minweights[*liftrhs] <= capacity - weight ) 3794 { 3795 z = *liftrhs; 3796 } 3797 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } 3798 */ 3799 else 3800 { 3801 int left; 3802 int right; 3803 int middle; 3804 3805 left = 0; 3806 right = (*liftrhs) + 1; 3807 while( left < right - 1) 3808 { 3809 middle = (left + right) / 2; 3810 assert(0 <= middle && middle < minweightslen); 3811 if( minweights[middle] <= capacity - weight ) 3812 left = middle; 3813 else 3814 right = middle; 3815 } 3816 assert(left == right - 1); 3817 assert(0 <= left && left < minweightslen); 3818 assert(minweights[left] <= capacity - weight ); 3819 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight); 3820 3821 /* now z = left */ 3822 z = left; 3823 assert(z <= *liftrhs); 3824 } 3825 3826 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */ 3827 liftcoef = (*liftrhs) - z; 3828 liftcoefs[liftvar] = liftcoef; 3829 assert(liftcoef >= 0 && liftcoef <= *liftrhs); 3830 3831 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */ 3832 if( liftcoef == 0 ) 3833 continue; 3834 3835 /* updates activity of current valid inequality */ 3836 (*cutact) += liftcoef * solvals[liftvar]; 3837 3838 /* updates minweight table: minweight_i+1[w] = 3839 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i 3840 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i 3841 */ 3842 for( w = *liftrhs; w >= 0; w-- ) 3843 { 3844 SCIP_Longint min; 3845 if( w < liftcoef ) 3846 { 3847 min = MIN(minweights[w], weight); 3848 minweights[w] = min; 3849 } 3850 else 3851 { 3852 assert(w >= liftcoef); 3853 min = MIN(minweights[w], minweights[w - liftcoef] + weight); 3854 minweights[w] = min; 3855 } 3856 } 3857 } 3858 3859 /* frees temporary memory */ 3860 SCIPfreeBufferArray(scip, &sortkeys); 3861 SCIPfreeBufferArray(scip, &minweights); 3862 3863 return SCIP_OKAY; 3864 } 3865 3866 /** adds two minweight values in a safe way, i.e,, ensures no overflow */ 3867 static 3868 SCIP_Longint safeAddMinweightsGUB( 3869 SCIP_Longint val1, /**< first value to add */ 3870 SCIP_Longint val2 /**< second value to add */ 3871 ) 3872 { 3873 assert(val1 >= 0); 3874 assert(val2 >= 0); 3875 3876 if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX ) 3877 return SCIP_LONGINT_MAX; 3878 else 3879 { 3880 assert(val1 <= SCIP_LONGINT_MAX - val2); 3881 return (val1 + val2); 3882 } 3883 } 3884 3885 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */ 3886 static 3887 void computeMinweightsGUB( 3888 SCIP_Longint* minweights, /**< minweight table to compute */ 3889 SCIP_Longint* finished, /**< given finished table */ 3890 SCIP_Longint* unfinished, /**< given unfinished table */ 3891 int minweightslen /**< length of minweight, finished, and unfinished tables */ 3892 ) 3893 { 3894 int w1; 3895 int w2; 3896 3897 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w}; 3898 * note that finished and unfished arrays sorted by non-decreasing weight 3899 */ 3900 3901 /* initialize minweight with w2 = 0 */ 3902 w2 = 0; 3903 assert(unfinished[w2] == 0); 3904 for( w1 = 0; w1 < minweightslen; w1++ ) 3905 minweights[w1] = finished[w1]; 3906 3907 /* consider w2 = 1, ..., minweightslen-1 */ 3908 for( w2 = 1; w2 < minweightslen; w2++ ) 3909 { 3910 if( unfinished[w2] >= SCIP_LONGINT_MAX ) 3911 break; 3912 3913 for( w1 = 0; w1 < minweightslen - w2; w1++ ) 3914 { 3915 SCIP_Longint temp; 3916 3917 temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]); 3918 if( temp <= minweights[w1+w2] ) 3919 minweights[w1+w2] = temp; 3920 } 3921 } 3922 } 3923 3924 /** lifts given inequality 3925 * sum_{j in C_1} x_j <= alpha_0 3926 * valid for 3927 * 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; 3928 * sum_{j in Q_i} x_j <= 1, forall i in I } 3929 * to a valid inequality 3930 * 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 3931 * <= alpha_0 + sum_{j in C_2} alpha_j 3932 * for 3933 * 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 }; 3934 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1, 3935 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and 3936 * sequential up-lifting for the variabels in GUB constraints in gubconsGR. 3937 */ 3938 static 3939 SCIP_RETCODE sequentialUpAndDownLiftingGUB( 3940 SCIP* scip, /**< SCIP data structure */ 3941 SCIP_GUBSET* gubset, /**< GUB set data structure */ 3942 SCIP_VAR** vars, /**< variables in knapsack constraint */ 3943 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */ 3944 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 3945 SCIP_Longint capacity, /**< capacity of knapsack */ 3946 SCIP_Real* solvals, /**< solution values of all knapsack variables */ 3947 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */ 3948 int* gubconsGC2, /**< GUBs in GC2 */ 3949 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */ 3950 int* gubconsGR, /**< GUBs in GR */ 3951 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */ 3952 int ngubconsGC2, /**< number of GUBs in GC2 */ 3953 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */ 3954 int ngubconsGR, /**< number of GUBs in GR */ 3955 int alpha0, /**< rights hand side of given valid inequality */ 3956 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */ 3957 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */ 3958 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */ 3959 int maxgubvarssize /**< maximal size of GUB constraints */ 3960 ) 3961 { 3962 SCIP_Longint* minweights; 3963 SCIP_Longint* finished; 3964 SCIP_Longint* unfinished; 3965 int* gubconsGOC1; 3966 int* gubconsGNC1; 3967 int* liftgubvars; 3968 SCIP_Longint fixedonesweight; 3969 SCIP_Longint weight; 3970 SCIP_Longint weightdiff1; 3971 SCIP_Longint weightdiff2; 3972 SCIP_Longint min; 3973 int minweightssize; 3974 int minweightslen; 3975 int nvars; 3976 int varidx; 3977 int liftgubconsidx; 3978 int liftvar; 3979 int sumliftcoef; 3980 int liftcoef; 3981 int ngubconsGOC1; 3982 int ngubconsGNC1; 3983 int left; 3984 int right; 3985 int middle; 3986 int nliftgubvars; 3987 int tmplen; 3988 int tmpsize; 3989 int j; 3990 int k; 3991 int w; 3992 int z; 3993 #ifndef NDEBUG 3994 int ngubconss; 3995 int nliftgubC1; 3996 3997 assert(gubset != NULL); 3998 ngubconss = gubset->ngubconss; 3999 #else 4000 assert(gubset != NULL); 4001 #endif 4002 4003 nvars = gubset->nvars; 4004 4005 assert(scip != NULL); 4006 assert(vars != NULL); 4007 assert(nvars >= 0); 4008 assert(weights != NULL); 4009 assert(capacity >= 0); 4010 assert(solvals != NULL); 4011 assert(gubconsGC1 != NULL); 4012 assert(gubconsGC2 != NULL); 4013 assert(gubconsGFC1 != NULL); 4014 assert(gubconsGR != NULL); 4015 assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed); 4016 assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed); 4017 assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed); 4018 assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed); 4019 assert(alpha0 >= 0); 4020 assert(liftcoefs != NULL); 4021 assert(cutact != NULL); 4022 assert(liftrhs != NULL); 4023 4024 minweightssize = ngubconsGC1+1; 4025 4026 /* allocates temporary memory */ 4027 SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) ); 4028 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) ); 4029 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) ); 4030 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) ); 4031 SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) ); 4032 SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) ); 4033 4034 /* initializes data structures */ 4035 BMSclearMemoryArray(liftcoefs, nvars); 4036 *cutact = 0.0; 4037 4038 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current 4039 * valid inequality 4040 */ 4041 ngubconsGOC1 = 0; 4042 ngubconsGNC1 = 0; 4043 for( j = 0; j < ngubconsGC1; j++ ) 4044 { 4045 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 ) 4046 { 4047 gubconsGOC1[ngubconsGOC1] = gubconsGC1[j]; 4048 ngubconsGOC1++; 4049 } 4050 else 4051 { 4052 assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1); 4053 gubconsGNC1[ngubconsGNC1] = gubconsGC1[j]; 4054 ngubconsGNC1++; 4055 } 4056 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars 4057 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ ) 4058 { 4059 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k]; 4060 assert(varidx >= 0 && varidx < nvars); 4061 assert(liftcoefs[varidx] == 0); 4062 4063 liftcoefs[varidx] = 1; 4064 (*cutact) += solvals[varidx]; 4065 } 4066 assert(k >= 1); 4067 } 4068 assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed); 4069 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1); 4070 4071 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|; 4072 * - finished_i[w] = 4073 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j 4074 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w 4075 * sum_{j in Q_k} x_j <= 1 4076 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1, 4077 * - unfinished_i[w] = 4078 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j 4079 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w 4080 * sum_{j in Q_k} x_j <= 1 4081 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1, 4082 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w}; 4083 */ 4084 4085 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables) 4086 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight. 4087 * 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 4088 * comes from the first variable in the GUB 4089 */ 4090 assert(ngubconsGOC1 <= ngubconsGC1); 4091 finished[0] = 0; 4092 for( w = 1; w <= ngubconsGOC1; w++ ) 4093 { 4094 liftgubconsidx = gubconsGOC1[w-1]; 4095 4096 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1); 4097 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1); 4098 4099 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0]; 4100 4101 assert(varidx >= 0 && varidx < nvars); 4102 assert(liftcoefs[varidx] == 1); 4103 4104 min = weights[varidx]; 4105 finished[w] = finished[w-1] + min; 4106 4107 #ifndef NDEBUG 4108 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars 4109 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ ) 4110 { 4111 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k]; 4112 assert(varidx >= 0 && varidx < nvars); 4113 assert(liftcoefs[varidx] == 1); 4114 assert(weights[varidx] >= min); 4115 } 4116 #endif 4117 } 4118 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ ) 4119 finished[w] = SCIP_LONGINT_MAX; 4120 4121 /* initialize unfinished table; note that variables in GNC1 GUBs 4122 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight. 4123 * 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 4124 * comes from the first variable in the GUB 4125 */ 4126 assert(ngubconsGNC1 <= ngubconsGC1); 4127 unfinished[0] = 0; 4128 for( w = 1; w <= ngubconsGNC1; w++ ) 4129 { 4130 liftgubconsidx = gubconsGNC1[w-1]; 4131 4132 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1); 4133 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1); 4134 4135 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0]; 4136 4137 assert(varidx >= 0 && varidx < nvars); 4138 assert(liftcoefs[varidx] == 1); 4139 4140 min = weights[varidx]; 4141 unfinished[w] = unfinished[w-1] + min; 4142 4143 #ifndef NDEBUG 4144 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars 4145 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ ) 4146 { 4147 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k]; 4148 assert(varidx >= 0 && varidx < nvars); 4149 assert(liftcoefs[varidx] == 1); 4150 assert(weights[varidx] >= min ); 4151 } 4152 #endif 4153 } 4154 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ ) 4155 unfinished[w] = SCIP_LONGINT_MAX; 4156 4157 /* initialize minweights table; note that variables in GC1 GUBs 4158 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight. 4159 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time 4160 * consuming) because is it has to be build using weights from C1 only. 4161 */ 4162 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1); 4163 minweights[0] = 0; 4164 for( w = 1; w <= ngubconsGC1; w++ ) 4165 { 4166 liftgubconsidx = gubconsGC1[w-1]; 4167 4168 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1 4169 || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1); 4170 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1); 4171 4172 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0]; 4173 4174 assert(varidx >= 0 && varidx < nvars); 4175 assert(liftcoefs[varidx] == 1); 4176 4177 min = weights[varidx]; 4178 minweights[w] = minweights[w-1] + min; 4179 4180 #ifndef NDEBUG 4181 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars 4182 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ ) 4183 { 4184 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k]; 4185 assert(varidx >= 0 && varidx < nvars); 4186 assert(liftcoefs[varidx] == 1); 4187 assert(weights[varidx] >= min); 4188 } 4189 #endif 4190 } 4191 minweightslen = ngubconsGC1 + 1; 4192 4193 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */ 4194 fixedonesweight = 0; 4195 for( j = 0; j < ngubconsGC2; j++ ) 4196 { 4197 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0]; 4198 4199 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1); 4200 assert(varidx >= 0 && varidx < nvars); 4201 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2); 4202 4203 fixedonesweight += weights[varidx]; 4204 } 4205 assert(fixedonesweight >= 0); 4206 4207 /* initializes right hand side of lifted valid inequality */ 4208 *liftrhs = alpha0; 4209 4210 /* sequentially up-lifts all variables in GFC1 GUBs */ 4211 for( j = 0; j < ngubconsGFC1; j++ ) 4212 { 4213 liftgubconsidx = gubconsGFC1[j]; 4214 assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss); 4215 4216 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and 4217 * compute minweight table via updated unfinished table and aleady upto date finished table; 4218 */ 4219 k = 0; 4220 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 ) 4221 { 4222 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1); 4223 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1); 4224 assert(ngubconsGNC1 > 0); 4225 4226 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that 4227 * are considered for the lifting, i.e., not capacity exceeding 4228 */ 4229 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars 4230 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ ) 4231 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k]; 4232 assert(k >= 1); 4233 4234 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight 4235 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB 4236 */ 4237 weight = weights[liftgubvars[0]]; 4238 4239 weightdiff2 = unfinished[ngubconsGNC1] - weight; 4240 unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX; 4241 for( w = ngubconsGNC1-1; w >= 1; w-- ) 4242 { 4243 weightdiff1 = weightdiff2; 4244 weightdiff2 = unfinished[w] - weight; 4245 4246 if( unfinished[w] < weightdiff1 ) 4247 unfinished[w] = weightdiff1; 4248 else 4249 break; 4250 } 4251 ngubconsGNC1--; 4252 4253 /* computes minweights table by combining unfished and fished tables */ 4254 computeMinweightsGUB(minweights, finished, unfinished, minweightslen); 4255 assert(minweights[0] == 0); 4256 } 4257 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and 4258 * are therefore not in the unfinished table 4259 */ 4260 else 4261 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF); 4262 4263 #ifndef NDEBUG 4264 nliftgubC1 = k; 4265 #endif 4266 nliftgubvars = k; 4267 sumliftcoef = 0; 4268 4269 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */ 4270 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ ) 4271 { 4272 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F 4273 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R ) 4274 { 4275 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k]; 4276 weight = weights[liftvar]; 4277 assert(weight > 0); 4278 assert(liftvar >= 0 && liftvar < nvars); 4279 assert(capacity - weight >= 0); 4280 4281 /* put variable into array of variables in GUB that are considered for the lifting, 4282 * i.e., not capacity exceeding 4283 */ 4284 liftgubvars[nliftgubvars] = liftvar; 4285 nliftgubvars++; 4286 4287 /* knapsack problem is infeasible: 4288 * sets z = 0 4289 */ 4290 if( capacity - fixedonesweight - weight < 0 ) 4291 { 4292 z = 0; 4293 } 4294 /* knapsack problem is feasible: 4295 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs, 4296 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i} 4297 */ 4298 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight ) 4299 { 4300 z = *liftrhs; 4301 } 4302 /* knapsack problem is feasible: 4303 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}} 4304 */ 4305 else 4306 { 4307 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight); 4308 left = 0; 4309 right = (*liftrhs) + 1; 4310 while( left < right - 1 ) 4311 { 4312 middle = (left + right) / 2; 4313 assert(0 <= middle && middle < minweightslen); 4314 if( minweights[middle] <= capacity - fixedonesweight - weight ) 4315 left = middle; 4316 else 4317 right = middle; 4318 } 4319 assert(left == right - 1); 4320 assert(0 <= left && left < minweightslen); 4321 assert(minweights[left] <= capacity - fixedonesweight - weight); 4322 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight); 4323 4324 /* now z = left */ 4325 z = left; 4326 assert(z <= *liftrhs); 4327 } 4328 4329 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */ 4330 liftcoef = (*liftrhs) - z; 4331 liftcoefs[liftvar] = liftcoef; 4332 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1); 4333 4334 /* updates activity of current valid inequality */ 4335 (*cutact) += liftcoef * solvals[liftvar]; 4336 4337 /* updates sum of all lifting coefficients in GUB */ 4338 sumliftcoef += liftcoefs[liftvar]; 4339 } 4340 else 4341 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED); 4342 } 4343 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */ 4344 assert(nliftgubvars > nliftgubC1); 4345 4346 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 4347 * and finished and minweight table can be updated easily as only C1 variables need to be considered; 4348 * not needed for GF GUBs 4349 */ 4350 if( sumliftcoef == 0 ) 4351 { 4352 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 ) 4353 { 4354 weight = weights[liftgubvars[0]]; 4355 /* update finished table and minweights table by applying special case of 4356 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB 4357 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB 4358 */ 4359 for( w = minweightslen-1; w >= 1; w-- ) 4360 { 4361 SCIP_Longint tmpval; 4362 4363 tmpval = safeAddMinweightsGUB(finished[w-1], weight); 4364 finished[w] = MIN(finished[w], tmpval); 4365 4366 tmpval = safeAddMinweightsGUB(minweights[w-1], weight); 4367 minweights[w] = MIN(minweights[w], tmpval); 4368 } 4369 } 4370 else 4371 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF); 4372 4373 continue; 4374 } 4375 4376 /* enlarges current minweights tables(finished, unfinished, minweights): 4377 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries 4378 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries 4379 * and sets minweights_i[w] = infinity for 4380 * 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 4381 */ 4382 tmplen = minweightslen; /* will be updated in enlargeMinweights() */ 4383 tmpsize = minweightssize; 4384 SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) ); 4385 tmplen = minweightslen; 4386 tmpsize = minweightssize; 4387 SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) ); 4388 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) ); 4389 4390 /* update finished table and minweight table; 4391 * note that instead of computing minweight table from updated finished and updated unfinished table again 4392 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here 4393 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight 4394 * not needed because only finished table changed at this point and the change was "adding" one weight) 4395 * 4396 * update formular for minweight table is: minweight_i+1[w] = 4397 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } } 4398 * formular for finished table has the same pattern. 4399 */ 4400 for( w = minweightslen-1; w >= 0; w-- ) 4401 { 4402 SCIP_Longint minminweight; 4403 SCIP_Longint minfinished; 4404 4405 for( k = 0; k < nliftgubvars; k++ ) 4406 { 4407 liftcoef = liftcoefs[liftgubvars[k]]; 4408 weight = weights[liftgubvars[k]]; 4409 4410 if( w < liftcoef ) 4411 { 4412 minfinished = MIN(finished[w], weight); 4413 minminweight = MIN(minweights[w], weight); 4414 4415 finished[w] = minfinished; 4416 minweights[w] = minminweight; 4417 } 4418 else 4419 { 4420 SCIP_Longint tmpval; 4421 4422 assert(w >= liftcoef); 4423 4424 tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight); 4425 minfinished = MIN(finished[w], tmpval); 4426 4427 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight); 4428 minminweight = MIN(minweights[w], tmpval); 4429 4430 finished[w] = minfinished; 4431 minweights[w] = minminweight; 4432 } 4433 } 4434 } 4435 assert(minweights[0] == 0); 4436 } 4437 assert(ngubconsGNC1 == 0); 4438 4439 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished; 4440 * therefore, only work with minweight table from here on 4441 */ 4442 4443 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */ 4444 for( j = 0; j < ngubconsGC2; j++ ) 4445 { 4446 liftgubconsidx = gubconsGC2[j]; 4447 4448 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss); 4449 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2); 4450 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1); 4451 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2); 4452 4453 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */ 4454 weight = weights[liftvar]; 4455 4456 assert(liftvar >= 0 && liftvar < nvars); 4457 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0)); 4458 assert(weight > 0); 4459 4460 /* uses binary search to find 4461 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}} 4462 */ 4463 left = 0; 4464 right = minweightslen; 4465 while( left < right - 1 ) 4466 { 4467 middle = (left + right) / 2; 4468 assert(0 <= middle && middle < minweightslen); 4469 if( minweights[middle] <= capacity - fixedonesweight + weight ) 4470 left = middle; 4471 else 4472 right = middle; 4473 } 4474 assert(left == right - 1); 4475 assert(0 <= left && left < minweightslen); 4476 assert(minweights[left] <= capacity - fixedonesweight + weight); 4477 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight); 4478 4479 /* now z = left */ 4480 z = left; 4481 assert(z >= *liftrhs); 4482 4483 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */ 4484 liftcoef = z - (*liftrhs); 4485 liftcoefs[liftvar] = liftcoef; 4486 assert(liftcoef >= 0); 4487 4488 /* updates sum of weights of variables fixed to one */ 4489 fixedonesweight -= weight; 4490 4491 /* updates right-hand side of current valid inequality */ 4492 (*liftrhs) += liftcoef; 4493 assert(*liftrhs >= alpha0); 4494 4495 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */ 4496 if( liftcoef == 0 ) 4497 continue; 4498 4499 /* updates activity of current valid inequality */ 4500 (*cutact) += liftcoef * solvals[liftvar]; 4501 4502 /* enlarges current minweight table: 4503 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries 4504 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries 4505 * and sets minweights_i[w] = infinity for 4506 * 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 4507 */ 4508 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) ); 4509 4510 /* updates minweight table: minweight_i+1[w] = 4511 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i 4512 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i 4513 */ 4514 for( w = minweightslen - 1; w >= 0; w-- ) 4515 { 4516 if( w < liftcoef ) 4517 { 4518 min = MIN(minweights[w], weight); 4519 minweights[w] = min; 4520 } 4521 else 4522 { 4523 SCIP_Longint tmpval; 4524 4525 assert(w >= liftcoef); 4526 4527 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight); 4528 min = MIN(minweights[w], tmpval); 4529 minweights[w] = min; 4530 } 4531 } 4532 } 4533 assert(fixedonesweight == 0); 4534 assert(*liftrhs >= alpha0); 4535 4536 /* sequentially up-lifts variables in GUB constraints in GR GUBs */ 4537 for( j = 0; j < ngubconsGR; j++ ) 4538 { 4539 liftgubconsidx = gubconsGR[j]; 4540 4541 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss); 4542 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR); 4543 4544 sumliftcoef = 0; 4545 nliftgubvars = 0; 4546 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ ) 4547 { 4548 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R ) 4549 { 4550 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k]; 4551 weight = weights[liftvar]; 4552 assert(weight > 0); 4553 assert(liftvar >= 0 && liftvar < nvars); 4554 assert(capacity - weight >= 0); 4555 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight); 4556 4557 /* put variable into array of variables in GUB that are considered for the lifting, 4558 * i.e., not capacity exceeding 4559 */ 4560 liftgubvars[nliftgubvars] = liftvar; 4561 nliftgubvars++; 4562 4563 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs, 4564 * if minweights_i[liftrhs] <= a_0 - a_{j_i} 4565 */ 4566 if( minweights[*liftrhs] <= capacity - weight ) 4567 { 4568 z = *liftrhs; 4569 } 4570 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } 4571 */ 4572 else 4573 { 4574 left = 0; 4575 right = (*liftrhs) + 1; 4576 while( left < right - 1 ) 4577 { 4578 middle = (left + right) / 2; 4579 assert(0 <= middle && middle < minweightslen); 4580 if( minweights[middle] <= capacity - weight ) 4581 left = middle; 4582 else 4583 right = middle; 4584 } 4585 assert(left == right - 1); 4586 assert(0 <= left && left < minweightslen); 4587 assert(minweights[left] <= capacity - weight); 4588 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight); 4589 4590 /* now z = left */ 4591 z = left; 4592 assert(z <= *liftrhs); 4593 } 4594 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */ 4595 liftcoef = (*liftrhs) - z; 4596 liftcoefs[liftvar] = liftcoef; 4597 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1); 4598 4599 /* updates activity of current valid inequality */ 4600 (*cutact) += liftcoef * solvals[liftvar]; 4601 4602 /* updates sum of all lifting coefficients in GUB */ 4603 sumliftcoef += liftcoefs[liftvar]; 4604 } 4605 else 4606 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED); 4607 } 4608 assert(nliftgubvars >= 1); /* at least one variable is in R */ 4609 4610 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */ 4611 if( sumliftcoef == 0 ) 4612 continue; 4613 4614 /* updates minweight table: minweight_i+1[w] = 4615 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } } 4616 */ 4617 for( w = *liftrhs; w >= 0; w-- ) 4618 { 4619 for( k = 0; k < nliftgubvars; k++ ) 4620 { 4621 liftcoef = liftcoefs[liftgubvars[k]]; 4622 weight = weights[liftgubvars[k]]; 4623 4624 if( w < liftcoef ) 4625 { 4626 min = MIN(minweights[w], weight); 4627 minweights[w] = min; 4628 } 4629 else 4630 { 4631 SCIP_Longint tmpval; 4632 4633 assert(w >= liftcoef); 4634 4635 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight); 4636 min = MIN(minweights[w], tmpval); 4637 minweights[w] = min; 4638 } 4639 } 4640 } 4641 assert(minweights[0] == 0); 4642 } 4643 4644 /* frees temporary memory */ 4645 SCIPfreeBufferArray(scip, &minweights); 4646 SCIPfreeBufferArray(scip, &finished); 4647 SCIPfreeBufferArray(scip, &unfinished); 4648 SCIPfreeBufferArray(scip, &liftgubvars); 4649 SCIPfreeBufferArray(scip, &gubconsGOC1 ); 4650 SCIPfreeBufferArray(scip, &gubconsGNC1); 4651 4652 return SCIP_OKAY; 4653 } 4654 4655 /** lifts given minimal cover inequality 4656 * \f[ 4657 * \sum_{j \in C} x_j \leq |C| - 1 4658 * \f] 4659 * valid for 4660 * \f[ 4661 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \} 4662 * \f] 4663 * to a valid inequality 4664 * \f[ 4665 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1 4666 * \f] 4667 * for 4668 * \f[ 4669 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \}; 4670 * \f] 4671 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$. 4672 */ 4673 static 4674 SCIP_RETCODE superadditiveUpLifting( 4675 SCIP* scip, /**< SCIP data structure */ 4676 SCIP_VAR** vars, /**< variables in knapsack constraint */ 4677 int nvars, /**< number of variables in knapsack constraint */ 4678 int ntightened, /**< number of variables with tightened upper bound */ 4679 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 4680 SCIP_Longint capacity, /**< capacity of knapsack */ 4681 SCIP_Real* solvals, /**< solution values of all problem variables */ 4682 int* covervars, /**< cover variables */ 4683 int* noncovervars, /**< noncover variables */ 4684 int ncovervars, /**< number of cover variables */ 4685 int nnoncovervars, /**< number of noncover variables */ 4686 SCIP_Longint coverweight, /**< weight of cover */ 4687 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */ 4688 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */ 4689 ) 4690 { 4691 SCIP_Longint* maxweightsums; 4692 SCIP_Longint* intervalends; 4693 SCIP_Longint* rhos; 4694 SCIP_Real* sortkeys; 4695 SCIP_Longint lambda; 4696 int j; 4697 int h; 4698 4699 assert(scip != NULL); 4700 assert(vars != NULL); 4701 assert(nvars >= 0); 4702 assert(weights != NULL); 4703 assert(capacity >= 0); 4704 assert(solvals != NULL); 4705 assert(covervars != NULL); 4706 assert(noncovervars != NULL); 4707 assert(ncovervars > 0 && ncovervars <= nvars); 4708 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened); 4709 assert(ncovervars + nnoncovervars == nvars - ntightened); 4710 assert(liftcoefs != NULL); 4711 assert(cutact != NULL); 4712 4713 /* allocates temporary memory */ 4714 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) ); 4715 SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) ); 4716 SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) ); 4717 SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) ); 4718 4719 /* initializes data structures */ 4720 BMSclearMemoryArray(liftcoefs, nvars); 4721 *cutact = 0.0; 4722 4723 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C| 4724 * and calculates activity of current valid inequality 4725 */ 4726 for( j = 0; j < ncovervars; j++ ) 4727 { 4728 assert(liftcoefs[covervars[j]] == 0.0); 4729 liftcoefs[covervars[j]] = 1.0; 4730 sortkeys[j] = (SCIP_Real) weights[covervars[j]]; 4731 (*cutact) += solvals[covervars[j]]; 4732 } 4733 SCIPsortDownRealInt(sortkeys, covervars, ncovervars); 4734 4735 /* calculates weight excess of cover C */ 4736 lambda = coverweight - capacity; 4737 assert(lambda > 0); 4738 4739 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */ 4740 maxweightsums[0] = 0; 4741 for( h = 1; h <= ncovervars; h++ ) 4742 { 4743 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]]; 4744 intervalends[h-1] = maxweightsums[h] - lambda; 4745 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda); 4746 } 4747 4748 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */ 4749 for( j = 0; j < nnoncovervars; j++ ) 4750 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]); 4751 SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars); 4752 4753 /* calculates lifting coefficient for all variables in N\C */ 4754 h = 0; 4755 for( j = 0; j < nnoncovervars; j++ ) 4756 { 4757 int liftvar; 4758 SCIP_Longint weight; 4759 SCIP_Real liftcoef; 4760 4761 liftvar = noncovervars[j]; 4762 weight = weights[liftvar]; 4763 4764 while( intervalends[h] < weight ) 4765 h++; 4766 4767 if( h == 0 ) 4768 liftcoef = h; 4769 else 4770 { 4771 if( weight <= intervalends[h-1] + rhos[h] ) 4772 { 4773 SCIP_Real tmp1; 4774 SCIP_Real tmp2; 4775 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight); 4776 tmp2 = (SCIP_Real) rhos[1]; 4777 liftcoef = h - ( tmp1 / tmp2 ); 4778 } 4779 else 4780 liftcoef = h; 4781 } 4782 4783 /* sets lifting coefficient */ 4784 assert(liftcoefs[liftvar] == 0.0); 4785 liftcoefs[liftvar] = liftcoef; 4786 4787 /* updates activity of current valid inequality */ 4788 (*cutact) += liftcoef * solvals[liftvar]; 4789 } 4790 4791 /* frees temporary memory */ 4792 SCIPfreeBufferArray(scip, &rhos); 4793 SCIPfreeBufferArray(scip, &intervalends); 4794 SCIPfreeBufferArray(scip, &maxweightsums); 4795 SCIPfreeBufferArray(scip, &sortkeys); 4796 4797 return SCIP_OKAY; 4798 } 4799 4800 4801 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for 4802 * given knapsack problem 4803 */ 4804 static 4805 SCIP_RETCODE separateSequLiftedMinimalCoverInequality( 4806 SCIP* scip, /**< SCIP data structure */ 4807 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */ 4808 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */ 4809 SCIP_VAR** vars, /**< variables in knapsack constraint */ 4810 int nvars, /**< number of variables in knapsack constraint */ 4811 int ntightened, /**< number of variables with tightened upper bound */ 4812 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 4813 SCIP_Longint capacity, /**< capacity of knapsack */ 4814 SCIP_Real* solvals, /**< solution values of all problem variables */ 4815 int* mincovervars, /**< mincover variables */ 4816 int* nonmincovervars, /**< nonmincover variables */ 4817 int nmincovervars, /**< number of mincover variables */ 4818 int nnonmincovervars, /**< number of nonmincover variables */ 4819 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */ 4820 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */ 4821 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */ 4822 int* ncuts /**< pointer to add up the number of found cuts */ 4823 ) 4824 { 4825 int* varsC1; 4826 int* varsC2; 4827 int* varsF; 4828 int* varsR; 4829 int nvarsC1; 4830 int nvarsC2; 4831 int nvarsF; 4832 int nvarsR; 4833 SCIP_Real cutact; 4834 int* liftcoefs; 4835 int liftrhs; 4836 4837 assert( cutoff != NULL ); 4838 *cutoff = FALSE; 4839 4840 /* allocates temporary memory */ 4841 SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) ); 4842 SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) ); 4843 SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) ); 4844 SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) ); 4845 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) ); 4846 4847 /* 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 4848 * as follows 4849 * C_2 = { j in C : x*_j = 1 } and 4850 * C_1 = C\C_2 4851 */ 4852 getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2); 4853 assert(nvarsC1 + nvarsC2 == nmincovervars); 4854 assert(nmincovervars > 0); 4855 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */ 4856 4857 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */ 4858 if( nvarsC1 < 2 && nvarsC2 > 0) 4859 { 4860 SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) ); 4861 assert(nvarsC1 >= 1); 4862 } 4863 assert(nvarsC2 == 0 || nvarsC1 >= 1); 4864 4865 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows 4866 * R = { j in N\C : x*_j = 0 } and 4867 * F = (N\C)\F 4868 */ 4869 getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR); 4870 assert(nvarsF + nvarsR == nnonmincovervars); 4871 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened); 4872 4873 /* lift cuts without GUB information */ 4874 if( gubset == NULL ) 4875 { 4876 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential 4877 * lifting procedure 4878 */ 4879 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) ); 4880 4881 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for 4882 * 4883 * 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 } 4884 * 4885 * 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 4886 * 4887 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 }, 4888 * 4889 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential 4890 * up-lifting for the variables in R according to the second level lifting sequence 4891 */ 4892 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2, 4893 varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) ); 4894 } 4895 /* lift cuts with GUB information */ 4896 else 4897 { 4898 int* gubconsGC1; 4899 int* gubconsGC2; 4900 int* gubconsGFC1; 4901 int* gubconsGR; 4902 int ngubconsGC1; 4903 int ngubconsGC2; 4904 int ngubconsGFC1; 4905 int ngubconsGR; 4906 int ngubconss; 4907 int nconstightened; 4908 int maxgubvarssize; 4909 4910 assert(nvars == gubset->nvars); 4911 4912 ngubconsGC1 = 0; 4913 ngubconsGC2 = 0; 4914 ngubconsGFC1 = 0; 4915 ngubconsGR = 0; 4916 ngubconss = gubset->ngubconss; 4917 nconstightened = 0; 4918 maxgubvarssize = 0; 4919 4920 /* allocates temporary memory */ 4921 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) ); 4922 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) ); 4923 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) ); 4924 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) ); 4925 4926 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of 4927 * the GUBs for the sequential GUB wise lifting procedure 4928 */ 4929 SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1, 4930 nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2, 4931 &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) ); 4932 4933 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for 4934 * 4935 * 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, 4936 * sum_{j in Q_i} x_j <= 1, forall i in I } 4937 * 4938 * 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 4939 * 4940 * 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 }, 4941 * 4942 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1, 4943 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and 4944 * sequential up-lifting for the variabels in GUB constraints in gubconsGR. 4945 */ 4946 SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1, 4947 gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR, 4948 MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) ); 4949 4950 /* frees temporary memory */ 4951 SCIPfreeBufferArray(scip, &gubconsGR); 4952 SCIPfreeBufferArray(scip, &gubconsGFC1); 4953 SCIPfreeBufferArray(scip, &gubconsGC2); 4954 SCIPfreeBufferArray(scip, &gubconsGC1); 4955 } 4956 4957 /* checks, if lifting yielded a violated cut */ 4958 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) ) 4959 { 4960 SCIP_ROW* row; 4961 char name[SCIP_MAXSTRLEN]; 4962 int j; 4963 4964 /* creates LP row */ 4965 assert( cons == NULL || sepa == NULL ); 4966 if ( cons != NULL ) 4967 { 4968 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons))); 4969 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, 4970 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE, 4971 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) ); 4972 } 4973 else if ( sepa != NULL ) 4974 { 4975 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa)); 4976 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) ); 4977 } 4978 else 4979 { 4980 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts); 4981 SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) ); 4982 } 4983 4984 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */ 4985 SCIP_CALL( SCIPcacheRowExtensions(scip, row) ); 4986 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened); 4987 for( j = 0; j < nvarsC1; j++ ) 4988 { 4989 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) ); 4990 } 4991 for( j = 0; j < nvarsC2; j++ ) 4992 { 4993 if( liftcoefs[varsC2[j]] > 0 ) 4994 { 4995 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) ); 4996 } 4997 } 4998 for( j = 0; j < nvarsF; j++ ) 4999 { 5000 if( liftcoefs[varsF[j]] > 0 ) 5001 { 5002 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) ); 5003 } 5004 } 5005 for( j = 0; j < nvarsR; j++ ) 5006 { 5007 if( liftcoefs[varsR[j]] > 0 ) 5008 { 5009 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) ); 5010 } 5011 } 5012 SCIP_CALL( SCIPflushRowExtensions(scip, row) ); 5013 5014 /* checks, if cut is violated enough */ 5015 if( SCIPisCutEfficacious(scip, sol, row) ) 5016 { 5017 if( cons != NULL ) 5018 { 5019 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 5020 } 5021 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) ); 5022 (*ncuts)++; 5023 } 5024 SCIP_CALL( SCIPreleaseRow(scip, &row) ); 5025 } 5026 5027 /* frees temporary memory */ 5028 SCIPfreeBufferArray(scip, &liftcoefs); 5029 SCIPfreeBufferArray(scip, &varsR); 5030 SCIPfreeBufferArray(scip, &varsF); 5031 SCIPfreeBufferArray(scip, &varsC2); 5032 SCIPfreeBufferArray(scip, &varsC1); 5033 5034 return SCIP_OKAY; 5035 } 5036 5037 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */ 5038 static 5039 SCIP_RETCODE separateSequLiftedExtendedWeightInequality( 5040 SCIP* scip, /**< SCIP data structure */ 5041 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */ 5042 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */ 5043 SCIP_VAR** vars, /**< variables in knapsack constraint */ 5044 int nvars, /**< number of variables in knapsack constraint */ 5045 int ntightened, /**< number of variables with tightened upper bound */ 5046 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 5047 SCIP_Longint capacity, /**< capacity of knapsack */ 5048 SCIP_Real* solvals, /**< solution values of all problem variables */ 5049 int* feassetvars, /**< variables in feasible set */ 5050 int* nonfeassetvars, /**< variables not in feasible set */ 5051 int nfeassetvars, /**< number of variables in feasible set */ 5052 int nnonfeassetvars, /**< number of variables not in feasible set */ 5053 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */ 5054 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */ 5055 int* ncuts /**< pointer to add up the number of found cuts */ 5056 ) 5057 { 5058 int* varsT1; 5059 int* varsT2; 5060 int* varsF; 5061 int* varsR; 5062 int* liftcoefs; 5063 SCIP_Real cutact; 5064 int nvarsT1; 5065 int nvarsT2; 5066 int nvarsF; 5067 int nvarsR; 5068 int liftrhs; 5069 int j; 5070 5071 assert( cutoff != NULL ); 5072 *cutoff = FALSE; 5073 5074 /* allocates temporary memory */ 5075 SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) ); 5076 SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) ); 5077 SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) ); 5078 SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) ); 5079 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) ); 5080 5081 /* 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 5082 * as follows 5083 * T_2 = { j in T : x*_j = 1 } and 5084 * T_1 = T\T_2 5085 */ 5086 getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2); 5087 assert(nvarsT1 + nvarsT2 == nfeassetvars); 5088 5089 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */ 5090 if( nvarsT1 == 0 && nvarsT2 > 0) 5091 { 5092 SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) ); 5093 assert(nvarsT1 == 1); 5094 } 5095 assert(nvarsT2 == 0 || nvarsT1 > 0); 5096 5097 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows 5098 * R = { j in N\T : x*_j = 0 } and 5099 * F = (N\T)\F 5100 */ 5101 getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR); 5102 assert(nvarsF + nvarsR == nnonfeassetvars); 5103 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened); 5104 5105 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential 5106 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it 5107 * is included in the sorting routine) 5108 */ 5109 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) ); 5110 5111 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for 5112 * 5113 * 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 } 5114 * 5115 * 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 5116 * 5117 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 }, 5118 * 5119 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential 5120 * up-lifting for the variabels in R according to the second level lifting sequence 5121 */ 5122 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR, 5123 nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) ); 5124 5125 /* checks, if lifting yielded a violated cut */ 5126 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) ) 5127 { 5128 SCIP_ROW* row; 5129 char name[SCIP_MAXSTRLEN]; 5130 5131 /* creates LP row */ 5132 assert( cons == NULL || sepa == NULL ); 5133 if( cons != NULL ) 5134 { 5135 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons))); 5136 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, 5137 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE, 5138 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) ); 5139 } 5140 else if ( sepa != NULL ) 5141 { 5142 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa)); 5143 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) ); 5144 } 5145 else 5146 { 5147 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts); 5148 SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) ); 5149 } 5150 5151 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */ 5152 SCIP_CALL( SCIPcacheRowExtensions(scip, row) ); 5153 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened); 5154 for( j = 0; j < nvarsT1; j++ ) 5155 { 5156 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) ); 5157 } 5158 for( j = 0; j < nvarsT2; j++ ) 5159 { 5160 if( liftcoefs[varsT2[j]] > 0 ) 5161 { 5162 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) ); 5163 } 5164 } 5165 for( j = 0; j < nvarsF; j++ ) 5166 { 5167 if( liftcoefs[varsF[j]] > 0 ) 5168 { 5169 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) ); 5170 } 5171 } 5172 for( j = 0; j < nvarsR; j++ ) 5173 { 5174 if( liftcoefs[varsR[j]] > 0 ) 5175 { 5176 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) ); 5177 } 5178 } 5179 SCIP_CALL( SCIPflushRowExtensions(scip, row) ); 5180 5181 /* checks, if cut is violated enough */ 5182 if( SCIPisCutEfficacious(scip, sol, row) ) 5183 { 5184 if( cons != NULL ) 5185 { 5186 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 5187 } 5188 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) ); 5189 (*ncuts)++; 5190 } 5191 SCIP_CALL( SCIPreleaseRow(scip, &row) ); 5192 } 5193 5194 /* frees temporary memory */ 5195 SCIPfreeBufferArray(scip, &liftcoefs); 5196 SCIPfreeBufferArray(scip, &varsR); 5197 SCIPfreeBufferArray(scip, &varsF); 5198 SCIPfreeBufferArray(scip, &varsT2); 5199 SCIPfreeBufferArray(scip, &varsT1); 5200 5201 return SCIP_OKAY; 5202 } 5203 5204 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */ 5205 static 5206 SCIP_RETCODE separateSupLiftedMinimalCoverInequality( 5207 SCIP* scip, /**< SCIP data structure */ 5208 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */ 5209 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */ 5210 SCIP_VAR** vars, /**< variables in knapsack constraint */ 5211 int nvars, /**< number of variables in knapsack constraint */ 5212 int ntightened, /**< number of variables with tightened upper bound */ 5213 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 5214 SCIP_Longint capacity, /**< capacity of knapsack */ 5215 SCIP_Real* solvals, /**< solution values of all problem variables */ 5216 int* mincovervars, /**< mincover variables */ 5217 int* nonmincovervars, /**< nonmincover variables */ 5218 int nmincovervars, /**< number of mincover variables */ 5219 int nnonmincovervars, /**< number of nonmincover variables */ 5220 SCIP_Longint mincoverweight, /**< weight of minimal cover */ 5221 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */ 5222 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */ 5223 int* ncuts /**< pointer to add up the number of found cuts */ 5224 ) 5225 { 5226 SCIP_Real* realliftcoefs; 5227 SCIP_Real cutact; 5228 int liftrhs; 5229 5230 assert( cutoff != NULL ); 5231 *cutoff = FALSE; 5232 cutact = 0.0; 5233 5234 /* allocates temporary memory */ 5235 SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) ); 5236 5237 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for 5238 * 5239 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 } 5240 * 5241 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for 5242 * 5243 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 }, 5244 * 5245 * uses superadditive up-lifting for the variables in N\C. 5246 */ 5247 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars, 5248 nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) ); 5249 liftrhs = nmincovervars - 1; 5250 5251 /* checks, if lifting yielded a violated cut */ 5252 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) ) 5253 { 5254 SCIP_ROW* row; 5255 char name[SCIP_MAXSTRLEN]; 5256 int j; 5257 5258 /* creates LP row */ 5259 assert( cons == NULL || sepa == NULL ); 5260 if ( cons != NULL ) 5261 { 5262 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons))); 5263 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, 5264 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE, 5265 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) ); 5266 } 5267 else if ( sepa != NULL ) 5268 { 5269 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa)); 5270 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) ); 5271 } 5272 else 5273 { 5274 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts); 5275 SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) ); 5276 } 5277 5278 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */ 5279 SCIP_CALL( SCIPcacheRowExtensions(scip, row) ); 5280 assert(nmincovervars + nnonmincovervars == nvars - ntightened); 5281 for( j = 0; j < nmincovervars; j++ ) 5282 { 5283 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) ); 5284 } 5285 for( j = 0; j < nnonmincovervars; j++ ) 5286 { 5287 assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0)); 5288 if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) ) 5289 { 5290 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) ); 5291 } 5292 } 5293 SCIP_CALL( SCIPflushRowExtensions(scip, row) ); 5294 5295 /* checks, if cut is violated enough */ 5296 if( SCIPisCutEfficacious(scip, sol, row) ) 5297 { 5298 if( cons != NULL ) 5299 { 5300 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 5301 } 5302 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) ); 5303 (*ncuts)++; 5304 } 5305 SCIP_CALL( SCIPreleaseRow(scip, &row) ); 5306 } 5307 5308 /* frees temporary memory */ 5309 SCIPfreeBufferArray(scip, &realliftcoefs); 5310 5311 return SCIP_OKAY; 5312 } 5313 5314 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen 5315 * 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 5316 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C; 5317 * note that all variables with x*_j = 1 will be removed last 5318 */ 5319 static 5320 SCIP_RETCODE makeCoverMinimal( 5321 SCIP* scip, /**< SCIP data structure */ 5322 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 5323 SCIP_Longint capacity, /**< capacity of knapsack */ 5324 SCIP_Real* solvals, /**< solution values of all problem variables */ 5325 int* covervars, /**< pointer to store cover variables */ 5326 int* noncovervars, /**< pointer to store noncover variables */ 5327 int* ncovervars, /**< pointer to store number of cover variables */ 5328 int* nnoncovervars, /**< pointer to store number of noncover variables */ 5329 SCIP_Longint* coverweight, /**< pointer to store weight of cover */ 5330 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */ 5331 ) 5332 { 5333 SORTKEYPAIR** sortkeypairs; 5334 SORTKEYPAIR** sortkeypairssorted; 5335 SCIP_Longint minweight; 5336 int nsortkeypairs; 5337 int minweightidx; 5338 int j; 5339 int k; 5340 5341 assert(scip != NULL); 5342 assert(covervars != NULL); 5343 assert(noncovervars != NULL); 5344 assert(ncovervars != NULL); 5345 assert(*ncovervars > 0); 5346 assert(nnoncovervars != NULL); 5347 assert(*nnoncovervars >= 0); 5348 assert(coverweight != NULL); 5349 assert(*coverweight > 0); 5350 assert(*coverweight > capacity); 5351 5352 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct 5353 * order */ 5354 nsortkeypairs = *ncovervars; 5355 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) ); 5356 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) ); 5357 5358 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e. 5359 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C 5360 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C 5361 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C 5362 */ 5363 assert(*ncovervars == nsortkeypairs); 5364 if( modtransused ) 5365 { 5366 for( j = 0; j < *ncovervars; j++ ) 5367 { 5368 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */ 5369 sortkeypairssorted[j] = sortkeypairs[j]; 5370 5371 sortkeypairs[j]->key1 = solvals[covervars[j]]; 5372 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]]; 5373 } 5374 } 5375 else 5376 { 5377 for( j = 0; j < *ncovervars; j++ ) 5378 { 5379 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */ 5380 sortkeypairssorted[j] = sortkeypairs[j]; 5381 5382 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]); 5383 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]); 5384 } 5385 } 5386 SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars); 5387 5388 /* gets j' with a_j' = min{ a_j : j in C } */ 5389 minweightidx = 0; 5390 minweight = weights[covervars[minweightidx]]; 5391 for( j = 1; j < *ncovervars; j++ ) 5392 { 5393 if( weights[covervars[j]] <= minweight ) 5394 { 5395 minweightidx = j; 5396 minweight = weights[covervars[minweightidx]]; 5397 } 5398 } 5399 assert(minweightidx >= 0 && minweightidx < *ncovervars); 5400 assert(minweight > 0 && minweight <= *coverweight); 5401 5402 j = 0; 5403 /* removes variables from C until the remaining variables form a minimal cover */ 5404 while( j < *ncovervars && ((*coverweight) - minweight > capacity) ) 5405 { 5406 assert(minweightidx >= j); 5407 assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j)); 5408 5409 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */ 5410 if( (*coverweight) - weights[covervars[j]] <= capacity ) 5411 { 5412 ++j; 5413 continue; 5414 } 5415 5416 /* adds j to N\C */ 5417 noncovervars[*nnoncovervars] = covervars[j]; 5418 (*nnoncovervars)++; 5419 5420 /* removes j from C */ 5421 (*coverweight) -= weights[covervars[j]]; 5422 for( k = j; k < (*ncovervars) - 1; k++ ) 5423 covervars[k] = covervars[k+1]; 5424 (*ncovervars)--; 5425 5426 /* updates j' with a_j' = min{ a_j : j in C } */ 5427 if( j == minweightidx ) 5428 { 5429 minweightidx = 0; 5430 minweight = weights[covervars[minweightidx]]; 5431 for( k = 1; k < *ncovervars; k++ ) 5432 { 5433 if( weights[covervars[k]] <= minweight ) 5434 { 5435 minweightidx = k; 5436 minweight = weights[covervars[minweightidx]]; 5437 } 5438 } 5439 assert(minweight > 0 && minweight <= *coverweight); 5440 assert(minweightidx >= 0 && minweightidx < *ncovervars); 5441 } 5442 else 5443 { 5444 assert(minweightidx > j); 5445 minweightidx--; 5446 } 5447 /* j needs to stay the same */ 5448 } 5449 assert((*coverweight) > capacity); 5450 assert((*coverweight) - minweight <= capacity); 5451 5452 /* frees temporary memory */ 5453 for( j = nsortkeypairs-1; j >= 0; j-- ) 5454 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */ 5455 SCIPfreeBufferArray(scip, &sortkeypairssorted); 5456 SCIPfreeBufferArray(scip, &sortkeypairs); 5457 5458 return SCIP_OKAY; 5459 } 5460 5461 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which 5462 * they were chosen to be in C_init: 5463 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init 5464 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init. 5465 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set 5466 * and all subsequent feasible sets. 5467 */ 5468 static 5469 SCIP_RETCODE getFeasibleSet( 5470 SCIP* scip, /**< SCIP data structure */ 5471 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */ 5472 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */ 5473 SCIP_VAR** vars, /**< variables in knapsack constraint */ 5474 int nvars, /**< number of variables in knapsack constraint */ 5475 int ntightened, /**< number of variables with tightened upper bound */ 5476 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 5477 SCIP_Longint capacity, /**< capacity of knapsack */ 5478 SCIP_Real* solvals, /**< solution values of all problem variables */ 5479 int* covervars, /**< pointer to store cover variables */ 5480 int* noncovervars, /**< pointer to store noncover variables */ 5481 int* ncovervars, /**< pointer to store number of cover variables */ 5482 int* nnoncovervars, /**< pointer to store number of noncover variables */ 5483 SCIP_Longint* coverweight, /**< pointer to store weight of cover */ 5484 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */ 5485 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */ 5486 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */ 5487 int* ncuts /**< pointer to add up the number of found cuts */ 5488 ) 5489 { 5490 SCIP_Real* sortkeys; 5491 int j; 5492 int k; 5493 5494 assert(scip != NULL); 5495 assert(covervars != NULL); 5496 assert(noncovervars != NULL); 5497 assert(ncovervars != NULL); 5498 assert(*ncovervars > 0); 5499 assert(nnoncovervars != NULL); 5500 assert(*nnoncovervars >= 0); 5501 assert(coverweight != NULL); 5502 assert(*coverweight > 0); 5503 assert(*coverweight > capacity); 5504 assert(*ncovervars + *nnoncovervars == nvars - ntightened); 5505 assert(cutoff != NULL); 5506 5507 *cutoff = FALSE; 5508 5509 /* allocates temporary memory */ 5510 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) ); 5511 5512 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e. 5513 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C 5514 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C 5515 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C 5516 */ 5517 if( modtransused ) 5518 { 5519 for( j = 0; j < *ncovervars; j++ ) 5520 { 5521 sortkeys[j] = solvals[covervars[j]]; 5522 assert(SCIPisFeasGE(scip, sortkeys[j], 0.0)); 5523 } 5524 } 5525 else 5526 { 5527 for( j = 0; j < *ncovervars; j++ ) 5528 { 5529 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]); 5530 assert(SCIPisFeasLE(scip, sortkeys[j], 0.0)); 5531 } 5532 } 5533 SCIPsortRealInt(sortkeys, covervars, *ncovervars); 5534 5535 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting; 5536 * in addition to an extended weight inequality this gives cardinality inequalities */ 5537 while( *ncovervars >= 2 ) 5538 { 5539 /* adds first element of C_init to N\C_init */ 5540 noncovervars[*nnoncovervars] = covervars[0]; 5541 (*nnoncovervars)++; 5542 5543 /* removes first element from C_init */ 5544 (*coverweight) -= weights[covervars[0]]; 5545 for( k = 0; k < (*ncovervars) - 1; k++ ) 5546 covervars[k] = covervars[k+1]; 5547 (*ncovervars)--; 5548 5549 assert(*ncovervars + *nnoncovervars == nvars - ntightened); 5550 if( (*coverweight) <= capacity ) 5551 { 5552 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, 5553 covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) ); 5554 } 5555 5556 /* stop if cover is too large */ 5557 if ( *ncovervars >= MAXCOVERSIZEITERLEWI ) 5558 break; 5559 } 5560 5561 /* frees temporary memory */ 5562 SCIPfreeBufferArray(scip, &sortkeys); 5563 5564 return SCIP_OKAY; 5565 } 5566 5567 /** separates different classes of valid inequalities for the 0-1 knapsack problem */ 5568 SCIP_RETCODE SCIPseparateKnapsackCuts( 5569 SCIP* scip, /**< SCIP data structure */ 5570 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */ 5571 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */ 5572 SCIP_VAR** vars, /**< variables in knapsack constraint */ 5573 int nvars, /**< number of variables in knapsack constraint */ 5574 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */ 5575 SCIP_Longint capacity, /**< capacity of knapsack */ 5576 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */ 5577 SCIP_Bool usegubs, /**< should GUB information be used for separation? */ 5578 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */ 5579 int* ncuts /**< pointer to add up the number of found cuts */ 5580 ) 5581 { 5582 SCIP_Real* solvals; 5583 int* covervars; 5584 int* noncovervars; 5585 SCIP_Bool coverfound; 5586 SCIP_Bool fractional; 5587 SCIP_Bool modtransused; 5588 SCIP_Longint coverweight; 5589 int ncovervars; 5590 int nnoncovervars; 5591 int ntightened; 5592 5593 assert(scip != NULL); 5594 assert(capacity >= 0); 5595 assert(cutoff != NULL); 5596 assert(ncuts != NULL); 5597 5598 *cutoff = FALSE; 5599 5600 if( nvars == 0 ) 5601 return SCIP_OKAY; 5602 5603 assert(vars != NULL); 5604 assert(nvars > 0); 5605 assert(weights != NULL); 5606 5607 /* increase age of constraint (age is reset to zero, if a cut was found) */ 5608 if( cons != NULL ) 5609 { 5610 SCIP_CALL( SCIPincConsAge(scip, cons) ); 5611 } 5612 5613 /* allocates temporary memory */ 5614 SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) ); 5615 SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) ); 5616 SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) ); 5617 5618 /* gets solution values of all problem variables */ 5619 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) ); 5620 5621 #ifdef SCIP_DEBUG 5622 { 5623 int i; 5624 5625 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n", 5626 cons == NULL ? "-" : SCIPconsGetName(cons)); 5627 for( i = 0; i < nvars; ++i ) 5628 { 5629 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]); 5630 } 5631 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity); 5632 } 5633 #endif 5634 5635 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information 5636 */ 5637 if( usegubs ) 5638 { 5639 SCIP_GUBSET* gubset; 5640 5641 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n"); 5642 5643 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */ 5644 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) ); 5645 5646 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */ 5647 SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) ); 5648 assert(gubset->ngubconss <= nvars); 5649 5650 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the 5651 * MODIFIED transformed separation problem and taking into account the following fixing: 5652 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and 5653 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0}, 5654 * if one exists 5655 */ 5656 modtransused = TRUE; 5657 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars, 5658 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) ); 5659 5660 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened); 5661 5662 /* if x* is not fractional we stop the separation routine */ 5663 if( !fractional ) 5664 { 5665 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n"); 5666 5667 /* frees memory for GUB set data structure */ 5668 GUBsetFree(scip, &gubset); 5669 5670 goto TERMINATE; 5671 } 5672 5673 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */ 5674 if( coverfound ) 5675 { 5676 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the 5677 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last 5678 */ 5679 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars, 5680 &nnoncovervars, &coverweight, modtransused) ); 5681 5682 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */ 5683 if( gubset->ngubconss < nvars ) 5684 { 5685 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */ 5686 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, 5687 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) ); 5688 } 5689 else 5690 { 5691 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial 5692 * GUB information 5693 */ 5694 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, 5695 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) ); 5696 } 5697 } 5698 5699 /* frees memory for GUB set data structure */ 5700 GUBsetFree(scip, &gubset); 5701 } 5702 else 5703 { 5704 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) 5705 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting)) 5706 */ 5707 5708 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the 5709 * MODIFIED transformed separation problem and taking into account the following fixing: 5710 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and 5711 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0}, 5712 * if one exists 5713 */ 5714 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n"); 5715 modtransused = TRUE; 5716 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars, 5717 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) ); 5718 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened); 5719 5720 /* if x* is not fractional we stop the separation routine */ 5721 if( !fractional ) 5722 goto TERMINATE; 5723 5724 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */ 5725 if( coverfound ) 5726 { 5727 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the 5728 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last 5729 */ 5730 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars, 5731 &nnoncovervars, &coverweight, modtransused) ); 5732 5733 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */ 5734 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, 5735 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) ); 5736 5737 if( USESUPADDLIFT ) /*lint !e506 !e774*/ 5738 { 5739 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n"); 5740 /* separates lifted minimal cover inequalities using superadditive up-lifting */ 5741 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, 5742 solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) ); 5743 } 5744 } 5745 } 5746 5747 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */ 5748 if ( ! (*cutoff) ) 5749 { 5750 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the 5751 * transformed separation problem and taking into account the following fixing: 5752 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and 5753 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0}, 5754 * if one exists 5755 */ 5756 SCIPdebugMsg(scip, "separate LEWI cuts:\n"); 5757 modtransused = FALSE; 5758 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars, 5759 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) ); 5760 assert(fractional); 5761 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened); 5762 5763 /* if no cover was found we stop the separation routine */ 5764 if( coverfound ) 5765 { 5766 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which 5767 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential 5768 * up- and down-lifting for this feasible set and all subsequent feasible sets. 5769 */ 5770 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars, 5771 &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) ); 5772 } 5773 } 5774 5775 TERMINATE: 5776 /* frees temporary memory */ 5777 SCIPfreeBufferArray(scip, &noncovervars); 5778 SCIPfreeBufferArray(scip, &covervars); 5779 SCIPfreeBufferArray(scip, &solvals); 5780 5781 return SCIP_OKAY; 5782 } 5783 5784 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */ 5785 SCIP_RETCODE SCIPseparateRelaxedKnapsack( 5786 SCIP* scip, /**< SCIP data structure */ 5787 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */ 5788 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */ 5789 int nknapvars, /**< number of variables in the continuous knapsack constraint */ 5790 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */ 5791 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */ 5792 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */ 5793 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */ 5794 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */ 5795 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */ 5796 int* ncuts /**< pointer to add up the number of found cuts */ 5797 ) 5798 { 5799 SCIP_VAR** binvars; 5800 SCIP_VAR** consvars; 5801 SCIP_Real* binvals; 5802 SCIP_Longint* consvals; 5803 SCIP_Longint minact; 5804 SCIP_Longint maxact; 5805 SCIP_Real intscalar; 5806 SCIP_Bool success; 5807 int nbinvars; 5808 int nconsvars; 5809 int i; 5810 5811 int* tmpindices; 5812 int tmp; 5813 SCIP_CONSHDLR* conshdlr; 5814 SCIP_CONSHDLRDATA* conshdlrdata; 5815 SCIP_Bool noknapsackconshdlr; 5816 SCIP_Bool usegubs; 5817 5818 assert(nknapvars > 0); 5819 assert(knapvars != NULL); 5820 assert(cutoff != NULL); 5821 5822 tmpindices = NULL; 5823 5824 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-"); 5825 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } ); 5826 5827 binvars = SCIPgetVars(scip); 5828 5829 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */ 5830 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip); 5831 5832 *cutoff = FALSE; 5833 5834 if( nbinvars == 0 ) 5835 return SCIP_OKAY; 5836 5837 /* set up data structures */ 5838 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) ); 5839 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) ); 5840 5841 /* get conshdlrdata to use cleared memory */ 5842 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME); 5843 if( conshdlr == NULL ) 5844 { 5845 noknapsackconshdlr = TRUE; 5846 usegubs = DEFAULT_USEGUBS; 5847 5848 SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) ); 5849 BMSclearMemoryArray(binvals, nbinvars); 5850 } 5851 else 5852 { 5853 noknapsackconshdlr = FALSE; 5854 conshdlrdata = SCIPconshdlrGetData(conshdlr); 5855 assert(conshdlrdata != NULL); 5856 usegubs = conshdlrdata->usegubs; 5857 5858 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) ); 5859 5860 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables 5861 * change their types to SCIP_VARTYPE_BINARY during presolving 5862 */ 5863 if( conshdlrdata->reals1size == 0 ) 5864 { 5865 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) ); 5866 conshdlrdata->reals1size = 1; 5867 conshdlrdata->reals1[0] = 0.0; 5868 } 5869 5870 assert(conshdlrdata->reals1size > 0); 5871 5872 /* next if condition should normally not be true, because it means that presolving has created more binary 5873 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would 5874 * transform all integers into their binary representation then it maybe happens 5875 */ 5876 if( conshdlrdata->reals1size < nbinvars ) 5877 { 5878 int oldsize = conshdlrdata->reals1size; 5879 5880 conshdlrdata->reals1size = nbinvars; 5881 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) ); 5882 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */ 5883 } 5884 binvals = conshdlrdata->reals1; 5885 5886 /* check for cleared array, all entries have to be zero */ 5887 #ifndef NDEBUG 5888 for( tmp = nbinvars - 1; tmp >= 0; --tmp ) 5889 { 5890 assert(binvals[tmp] == 0); 5891 } 5892 #endif 5893 } 5894 5895 tmp = 0; 5896 5897 /* relax continuous knapsack constraint: 5898 * 1. make all variables binary: 5899 * if x_j is continuous or integer variable substitute: 5900 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z 5901 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z 5902 * 2. convert coefficients of all variables to positive integers: 5903 * - scale all coefficients a_j to a~_j integral 5904 * - substitute x~_j = 1 - x_j if a~_j < 0 5905 */ 5906 5907 /* replace integer and continuous variables with binary variables */ 5908 for( i = 0; i < nknapvars; i++ ) 5909 { 5910 SCIP_VAR* var; 5911 5912 var = knapvars[i]; 5913 5914 if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) ) 5915 { 5916 SCIP_Real solval; 5917 assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars); 5918 5919 solval = SCIPgetSolVal(scip, sol, var); 5920 5921 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */ 5922 if( SCIPisFeasLT(scip, solval, 0.0 ) 5923 || SCIPisFeasGT(scip, solval, 1.0) ) 5924 { 5925 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n", 5926 solval, SCIPvarGetName(var)); 5927 goto TERMINATE; 5928 } 5929 5930 binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i]; 5931 if( !noknapsackconshdlr ) 5932 { 5933 assert(tmpindices != NULL); 5934 5935 tmpindices[tmp] = SCIPvarGetProbindex(var); 5936 ++tmp; 5937 } 5938 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var)); 5939 } 5940 else if( valscale * knapvals[i] > 0.0 ) 5941 { 5942 SCIP_VAR** zvlb; 5943 SCIP_Real* bvlb; 5944 SCIP_Real* dvlb; 5945 SCIP_Real bestlbsol; 5946 int bestlbtype; 5947 int nvlb; 5948 int j; 5949 5950 /* a_j > 0: substitution with lb or vlb */ 5951 nvlb = SCIPvarGetNVlbs(var); 5952 zvlb = SCIPvarGetVlbVars(var); 5953 bvlb = SCIPvarGetVlbCoefs(var); 5954 dvlb = SCIPvarGetVlbConstants(var); 5955 5956 /* search for lb or vlb with maximal bound value */ 5957 bestlbsol = SCIPvarGetLbGlobal(var); 5958 bestlbtype = -1; 5959 for( j = 0; j < nvlb; j++ ) 5960 { 5961 /* use only numerical stable vlb with binary variable z */ 5962 if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF ) 5963 { 5964 SCIP_Real vlbsol; 5965 5966 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) || 5967 (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ) 5968 { 5969 *cutoff = TRUE; 5970 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n", 5971 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), 5972 bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]); 5973 goto TERMINATE; 5974 } 5975 5976 assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars); 5977 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j]; 5978 if( SCIPisGE(scip, vlbsol, bestlbsol) ) 5979 { 5980 bestlbsol = vlbsol; 5981 bestlbtype = j; 5982 } 5983 } 5984 } 5985 5986 /* if no lb or vlb with binary variable was found, we have to abort */ 5987 if( SCIPisInfinity(scip, -bestlbsol) ) 5988 goto TERMINATE; 5989 5990 if( bestlbtype == -1 ) 5991 { 5992 rhs -= valscale * knapvals[i] * bestlbsol; 5993 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n", 5994 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs); 5995 } 5996 else 5997 { 5998 assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars); 5999 rhs -= valscale * knapvals[i] * dvlb[bestlbtype]; 6000 binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype]; 6001 6002 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) ) 6003 goto TERMINATE; 6004 6005 if( !noknapsackconshdlr ) 6006 { 6007 assert(tmpindices != NULL); 6008 6009 tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]); 6010 ++tmp; 6011 } 6012 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n", 6013 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), 6014 bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]), 6015 SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs); 6016 } 6017 } 6018 else 6019 { 6020 SCIP_VAR** zvub; 6021 SCIP_Real* bvub; 6022 SCIP_Real* dvub; 6023 SCIP_Real bestubsol; 6024 int bestubtype; 6025 int nvub; 6026 int j; 6027 6028 assert(valscale * knapvals[i] < 0.0); 6029 6030 /* a_j < 0: substitution with ub or vub */ 6031 nvub = SCIPvarGetNVubs(var); 6032 zvub = SCIPvarGetVubVars(var); 6033 bvub = SCIPvarGetVubCoefs(var); 6034 dvub = SCIPvarGetVubConstants(var); 6035 6036 /* search for ub or vub with minimal bound value */ 6037 bestubsol = SCIPvarGetUbGlobal(var); 6038 bestubtype = -1; 6039 for( j = 0; j < nvub; j++ ) 6040 { 6041 /* use only numerical stable vub with active binary variable z */ 6042 if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF ) 6043 { 6044 SCIP_Real vubsol; 6045 6046 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) || 6047 (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ) 6048 { 6049 *cutoff = TRUE; 6050 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n", 6051 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), 6052 bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]); 6053 goto TERMINATE; 6054 } 6055 6056 assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars); 6057 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j]; 6058 if( SCIPisLE(scip, vubsol, bestubsol) ) 6059 { 6060 bestubsol = vubsol; 6061 bestubtype = j; 6062 } 6063 } 6064 } 6065 6066 /* if no ub or vub with binary variable was found, we have to abort */ 6067 if( SCIPisInfinity(scip, bestubsol) ) 6068 goto TERMINATE; 6069 6070 if( bestubtype == -1 ) 6071 { 6072 rhs -= valscale * knapvals[i] * bestubsol; 6073 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n", 6074 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs); 6075 } 6076 else 6077 { 6078 assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars); 6079 rhs -= valscale * knapvals[i] * dvub[bestubtype]; 6080 binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype]; 6081 6082 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) ) 6083 goto TERMINATE; 6084 6085 if( !noknapsackconshdlr ) 6086 { 6087 assert(tmpindices != NULL); 6088 6089 tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]); 6090 ++tmp; 6091 } 6092 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n", 6093 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), 6094 bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]), 6095 SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs); 6096 } 6097 } 6098 } 6099 6100 /* convert coefficients of all (now binary) variables to positive integers: 6101 * - make all coefficients integral 6102 * - make all coefficients positive (substitute negated variable) 6103 */ 6104 nconsvars = 0; 6105 6106 /* calculate scalar which makes all coefficients integral in relative allowed difference in between 6107 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA 6108 */ 6109 SCIP_CALL( SCIPcalcIntegralScalar(binvals, nbinvars, -SCIPepsilon(scip), KNAPSACKRELAX_MAXDELTA, 6110 KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) ); 6111 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar); 6112 6113 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */ 6114 if( !success ) 6115 intscalar = 1.0; 6116 6117 /* make all coefficients integral and positive: 6118 * - scale a~_j = a_j * intscalar 6119 * - substitute x~_j = 1 - x_j if a~_j < 0 6120 */ 6121 rhs = rhs * intscalar; 6122 6123 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs); 6124 minact = 0; 6125 maxact = 0; 6126 for( i = 0; i < nbinvars; i++ ) 6127 { 6128 SCIP_VAR* var; 6129 SCIP_Longint val; 6130 6131 val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar); 6132 if( val == 0 ) 6133 continue; 6134 6135 if( val > 0 ) 6136 { 6137 var = binvars[i]; 6138 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n", 6139 val, SCIPvarGetName(var), binvals[i], rhs); 6140 } 6141 else 6142 { 6143 assert(val < 0); 6144 6145 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) ); 6146 val = -val; /*lint !e2704*/ 6147 rhs += val; 6148 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n", 6149 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs); 6150 } 6151 6152 if( SCIPvarGetLbLocal(var) > 0.5 ) 6153 minact += val; 6154 if( SCIPvarGetUbLocal(var) > 0.5 ) 6155 maxact += val; 6156 consvals[nconsvars] = val; 6157 consvars[nconsvars] = var; 6158 nconsvars++; 6159 } 6160 6161 if( nconsvars > 0 ) 6162 { 6163 SCIP_Longint capacity; 6164 6165 assert(consvars != NULL); 6166 assert(consvals != NULL); 6167 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs); 6168 6169 #ifdef SCIP_DEBUG 6170 { 6171 SCIP_Real act; 6172 6173 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-"); 6174 act = 0.0; 6175 for( i = 0; i < nconsvars; ++i ) 6176 { 6177 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]), 6178 SCIPgetSolVal(scip, sol, consvars[i])); 6179 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]); 6180 } 6181 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n", 6182 capacity, rhs, act, minact, maxact); 6183 } 6184 #endif 6185 6186 if( minact > capacity ) 6187 { 6188 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n"); 6189 *cutoff = TRUE; 6190 goto TERMINATE; 6191 } 6192 6193 if( maxact > capacity ) 6194 { 6195 /* separate lifted cut from relaxed knapsack constraint */ 6196 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) ); 6197 } 6198 } 6199 6200 TERMINATE: 6201 /* free data structures */ 6202 if( noknapsackconshdlr) 6203 { 6204 SCIPfreeBufferArray(scip, &binvals); 6205 } 6206 else 6207 { 6208 /* clear binvals */ 6209 for( --tmp; tmp >= 0; --tmp) 6210 { 6211 assert(tmpindices != NULL); 6212 binvals[tmpindices[tmp]] = 0; 6213 } 6214 SCIPfreeBufferArray(scip, &tmpindices); 6215 } 6216 SCIPfreeBufferArray(scip, &consvals); 6217 SCIPfreeBufferArray(scip, &consvars); 6218 6219 return SCIP_OKAY; 6220 } 6221 6222 /** separates given knapsack constraint */ 6223 static 6224 SCIP_RETCODE separateCons( 6225 SCIP* scip, /**< SCIP data structure */ 6226 SCIP_CONS* cons, /**< knapsack constraint */ 6227 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */ 6228 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */ 6229 SCIP_Bool usegubs, /**< should GUB information be used for separation? */ 6230 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */ 6231 int* ncuts /**< pointer to add up the number of found cuts */ 6232 ) 6233 { 6234 SCIP_CONSDATA* consdata; 6235 SCIP_Bool violated; 6236 6237 assert(ncuts != NULL); 6238 assert(cutoff != NULL); 6239 *cutoff = FALSE; 6240 6241 consdata = SCIPconsGetData(cons); 6242 assert(consdata != NULL); 6243 6244 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons)); 6245 6246 /* check knapsack constraint itself for feasibility */ 6247 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) ); 6248 6249 if( violated ) 6250 { 6251 /* add knapsack constraint as LP row to the LP */ 6252 SCIP_CALL( addRelaxation(scip, cons, cutoff) ); 6253 (*ncuts)++; 6254 } 6255 else if( sepacuts ) 6256 { 6257 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights, 6258 consdata->capacity, sol, usegubs, cutoff, ncuts) ); 6259 } 6260 6261 return SCIP_OKAY; 6262 } 6263 6264 /** adds coefficient to constraint data */ 6265 static 6266 SCIP_RETCODE addCoef( 6267 SCIP* scip, /**< SCIP data structure */ 6268 SCIP_CONS* cons, /**< knapsack constraint */ 6269 SCIP_VAR* var, /**< variable to add to knapsack */ 6270 SCIP_Longint weight /**< weight of variable in knapsack */ 6271 ) 6272 { 6273 SCIP_CONSDATA* consdata; 6274 6275 consdata = SCIPconsGetData(cons); 6276 assert(consdata != NULL); 6277 assert(SCIPvarIsBinary(var)); 6278 assert(weight > 0); 6279 6280 /* add the new coefficient to the LP row */ 6281 if( consdata->row != NULL ) 6282 { 6283 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) ); 6284 } 6285 6286 /* check for fixed variable */ 6287 if( SCIPvarGetLbGlobal(var) > 0.5 ) 6288 { 6289 /* variable is fixed to one: reduce capacity */ 6290 consdata->capacity -= weight; 6291 } 6292 else if( SCIPvarGetUbGlobal(var) > 0.5 ) 6293 { 6294 SCIP_Bool negated; 6295 6296 /* get binary representative of variable */ 6297 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) ); 6298 6299 /* insert coefficient */ 6300 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) ); 6301 consdata->vars[consdata->nvars] = var; 6302 consdata->weights[consdata->nvars] = weight; 6303 consdata->nvars++; 6304 6305 /* capture variable */ 6306 SCIP_CALL( SCIPcaptureVar(scip, var) ); 6307 6308 /* install the rounding locks of variable */ 6309 SCIP_CALL( lockRounding(scip, cons, var) ); 6310 6311 /* catch events */ 6312 if( SCIPconsIsTransformed(cons) ) 6313 { 6314 SCIP_CONSHDLRDATA* conshdlrdata; 6315 6316 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons)); 6317 assert(conshdlrdata != NULL); 6318 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) ); 6319 SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTTYPE_KNAPSACK, 6320 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1], 6321 &consdata->eventdata[consdata->nvars-1]->filterpos) ); 6322 6323 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR ) 6324 consdata->existmultaggr = TRUE; 6325 6326 /* mark constraint to be propagated and presolved */ 6327 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) ); 6328 consdata->presolvedtiming = 0; 6329 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */ 6330 } 6331 6332 /* update weight sums */ 6333 updateWeightSums(consdata, var, weight); 6334 6335 consdata->sorted = FALSE; 6336 consdata->cliquepartitioned = FALSE; 6337 consdata->negcliquepartitioned = FALSE; 6338 consdata->merged = FALSE; 6339 } 6340 6341 return SCIP_OKAY; 6342 } 6343 6344 /** deletes coefficient at given position from constraint data */ 6345 static 6346 SCIP_RETCODE delCoefPos( 6347 SCIP* scip, /**< SCIP data structure */ 6348 SCIP_CONS* cons, /**< knapsack constraint */ 6349 int pos /**< position of coefficient to delete */ 6350 ) 6351 { 6352 SCIP_CONSDATA* consdata; 6353 SCIP_VAR* var; 6354 6355 consdata = SCIPconsGetData(cons); 6356 assert(consdata != NULL); 6357 assert(0 <= pos && pos < consdata->nvars); 6358 6359 var = consdata->vars[pos]; 6360 assert(var != NULL); 6361 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var)); 6362 6363 /* delete the coefficient from the LP row */ 6364 if( consdata->row != NULL ) 6365 { 6366 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) ); 6367 } 6368 6369 /* remove the rounding locks of variable */ 6370 SCIP_CALL( unlockRounding(scip, cons, var) ); 6371 6372 /* drop events and mark constraint to be propagated and presolved */ 6373 if( SCIPconsIsTransformed(cons) ) 6374 { 6375 SCIP_CONSHDLRDATA* conshdlrdata; 6376 6377 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons)); 6378 assert(conshdlrdata != NULL); 6379 SCIP_CALL( SCIPdropVarEvent(scip, var, EVENTTYPE_KNAPSACK, 6380 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) ); 6381 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) ); 6382 6383 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) ); 6384 consdata->presolvedtiming = 0; 6385 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1); 6386 } 6387 6388 /* decrease weight sums */ 6389 updateWeightSums(consdata, var, -consdata->weights[pos]); 6390 6391 /* move the last variable to the free slot */ 6392 consdata->vars[pos] = consdata->vars[consdata->nvars-1]; 6393 consdata->weights[pos] = consdata->weights[consdata->nvars-1]; 6394 if( consdata->eventdata != NULL ) 6395 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1]; 6396 6397 /* release variable */ 6398 SCIP_CALL( SCIPreleaseVar(scip, &var) ); 6399 6400 /* try to use old clique partitions */ 6401 if( consdata->cliquepartitioned ) 6402 { 6403 assert(consdata->cliquepartition != NULL); 6404 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't 6405 * change the clique number */ 6406 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 ) 6407 { 6408 int oldcliqenum; 6409 6410 oldcliqenum = consdata->cliquepartition[pos]; 6411 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1]; 6412 6413 /* the following if and else cases assure that we have increasing clique numbers */ 6414 if( consdata->cliquepartition[pos] > pos ) 6415 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */ 6416 else 6417 { 6418 int i; 6419 int cliquenumbefore; 6420 6421 /* if the old clique number was greater than the new one we have to check that before a bigger clique number 6422 * occurs the same as the old one is still in the cliquepartition */ 6423 if( oldcliqenum > consdata->cliquepartition[pos] ) 6424 { 6425 for( i = 0; i < consdata->nvars; ++i ) 6426 if( oldcliqenum == consdata->cliquepartition[i] ) 6427 break; 6428 else if( oldcliqenum < consdata->cliquepartition[i] ) 6429 { 6430 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */ 6431 break; 6432 } 6433 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with 6434 * the biggest index, so decrease the number of cliques 6435 */ 6436 if( i == consdata->nvars ) 6437 --(consdata->ncliques); 6438 } 6439 /* if the old clique number was smaller than the new one we have to check the front for an element with 6440 * clique number minus 1 */ 6441 else if( oldcliqenum < consdata->cliquepartition[pos] ) 6442 { 6443 cliquenumbefore = consdata->cliquepartition[pos] - 1; 6444 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/ 6445 6446 if( i < cliquenumbefore ) 6447 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */ 6448 } 6449 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */ 6450 else if( pos == consdata->nvars - 1) 6451 { 6452 cliquenumbefore = consdata->cliquepartition[pos]; 6453 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/ 6454 6455 if( i < cliquenumbefore ) 6456 --(consdata->ncliques); 6457 } 6458 /* if the old clique number is equal to the new one the cliquepartition should be ok */ 6459 } 6460 } 6461 else 6462 --(consdata->ncliques); 6463 } 6464 6465 if( consdata->negcliquepartitioned ) 6466 { 6467 assert(consdata->negcliquepartition != NULL); 6468 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't 6469 * change the clique number */ 6470 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 ) 6471 { 6472 int oldcliqenum; 6473 6474 oldcliqenum = consdata->negcliquepartition[pos]; 6475 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1]; 6476 6477 /* the following if and else cases assure that we have increasing clique numbers */ 6478 if( consdata->negcliquepartition[pos] > pos ) 6479 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */ 6480 else 6481 { 6482 int i; 6483 int cliquenumbefore; 6484 6485 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number 6486 * occurs, the same as the old one occurs */ 6487 if( oldcliqenum > consdata->negcliquepartition[pos] ) 6488 { 6489 for( i = 0; i < consdata->nvars; ++i ) 6490 if( oldcliqenum == consdata->negcliquepartition[i] ) 6491 break; 6492 else if( oldcliqenum < consdata->negcliquepartition[i] ) 6493 { 6494 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */ 6495 break; 6496 } 6497 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with 6498 * the biggest index, so decrease the number of negated cliques 6499 */ 6500 if( i == consdata->nvars ) 6501 --(consdata->nnegcliques); 6502 } 6503 /* if the old clique number was smaller than the new one we have to check the front for an element with 6504 * clique number minus 1 */ 6505 else if( oldcliqenum < consdata->negcliquepartition[pos] ) 6506 { 6507 cliquenumbefore = consdata->negcliquepartition[pos] - 1; 6508 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/ 6509 6510 if( i < cliquenumbefore ) 6511 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */ 6512 } 6513 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */ 6514 else if( pos == consdata->nvars - 1) 6515 { 6516 cliquenumbefore = consdata->negcliquepartition[pos]; 6517 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/ 6518 6519 if( i < cliquenumbefore ) 6520 --(consdata->nnegcliques); 6521 } 6522 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */ 6523 } 6524 } 6525 else 6526 --(consdata->nnegcliques); 6527 } 6528 6529 --(consdata->nvars); 6530 6531 return SCIP_OKAY; 6532 } 6533 6534 /** removes all items with weight zero from knapsack constraint */ 6535 static 6536 SCIP_RETCODE removeZeroWeights( 6537 SCIP* scip, /**< SCIP data structure */ 6538 SCIP_CONS* cons /**< knapsack constraint */ 6539 ) 6540 { 6541 SCIP_CONSDATA* consdata; 6542 int v; 6543 6544 consdata = SCIPconsGetData(cons); 6545 assert(consdata != NULL); 6546 6547 for( v = consdata->nvars-1; v >= 0; --v ) 6548 { 6549 if( consdata->weights[v] == 0 ) 6550 { 6551 SCIP_CALL( delCoefPos(scip, cons, v) ); 6552 } 6553 } 6554 6555 return SCIP_OKAY; 6556 } 6557 6558 /* perform deletion of variables in all constraints of the constraint handler */ 6559 static 6560 SCIP_RETCODE performVarDeletions( 6561 SCIP* scip, /**< SCIP data structure */ 6562 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 6563 SCIP_CONS** conss, /**< array of constraints */ 6564 int nconss /**< number of constraints */ 6565 ) 6566 { 6567 SCIP_CONSDATA* consdata; 6568 int i; 6569 int v; 6570 6571 assert(scip != NULL); 6572 assert(conshdlr != NULL); 6573 assert(conss != NULL); 6574 assert(nconss >= 0); 6575 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 6576 6577 /* iterate over all constraints */ 6578 for( i = 0; i < nconss; i++ ) 6579 { 6580 consdata = SCIPconsGetData(conss[i]); 6581 6582 /* constraint is marked, that some of its variables were deleted */ 6583 if( consdata->varsdeleted ) 6584 { 6585 /* iterate over all variables of the constraint and delete them from the constraint */ 6586 for( v = consdata->nvars - 1; v >= 0; --v ) 6587 { 6588 if( SCIPvarIsDeleted(consdata->vars[v]) ) 6589 { 6590 SCIP_CALL( delCoefPos(scip, conss[i], v) ); 6591 } 6592 } 6593 consdata->varsdeleted = FALSE; 6594 } 6595 } 6596 6597 return SCIP_OKAY; 6598 } 6599 6600 /** replaces multiple occurrences of a variable or its negation by a single coefficient */ 6601 static 6602 SCIP_RETCODE mergeMultiples( 6603 SCIP* scip, /**< SCIP data structure */ 6604 SCIP_CONS* cons, /**< knapsack constraint */ 6605 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */ 6606 ) 6607 { 6608 SCIP_CONSDATA* consdata; 6609 int v; 6610 int prev; 6611 6612 assert(scip != NULL); 6613 assert(cons != NULL); 6614 assert(cutoff != NULL); 6615 6616 consdata = SCIPconsGetData(cons); 6617 assert(consdata != NULL); 6618 6619 *cutoff = FALSE; 6620 6621 if( consdata->merged ) 6622 return SCIP_OKAY; 6623 6624 if( consdata->nvars <= 1 ) 6625 { 6626 consdata->merged = TRUE; 6627 return SCIP_OKAY; 6628 } 6629 6630 assert(consdata->vars != NULL || consdata->nvars == 0); 6631 6632 /* sorting array after indices of variables, that's only for faster merging */ 6633 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights, 6634 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars); 6635 6636 /* knapsack-sorting (decreasing weights) now lost */ 6637 consdata->sorted = FALSE; 6638 6639 v = consdata->nvars - 1; 6640 prev = v - 1; 6641 /* loop backwards through the items: deletion only affects rear items */ 6642 while( prev >= 0 ) 6643 { 6644 SCIP_VAR* var1; 6645 SCIP_VAR* var2; 6646 SCIP_Bool negated1; 6647 SCIP_Bool negated2; 6648 6649 negated1 = FALSE; 6650 negated2 = FALSE; 6651 6652 var1 = consdata->vars[v]; 6653 assert(SCIPvarIsBinary(var1)); 6654 assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED); 6655 if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED ) 6656 { 6657 var1 = SCIPvarGetNegatedVar(var1); 6658 negated1 = TRUE; 6659 } 6660 assert(var1 != NULL); 6661 6662 var2 = consdata->vars[prev]; 6663 assert(SCIPvarIsBinary(var2)); 6664 assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED); 6665 if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED ) 6666 { 6667 var2 = SCIPvarGetNegatedVar(var2); 6668 negated2 = TRUE; 6669 } 6670 assert(var2 != NULL); 6671 6672 if( var1 == var2 ) 6673 { 6674 /* both variables are either active or negated */ 6675 if( negated1 == negated2 ) 6676 { 6677 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */ 6678 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]); 6679 SCIP_CALL( delCoefPos(scip, cons, v) ); 6680 } 6681 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity, 6682 * and delete item of smaller weight 6683 */ 6684 else if( consdata->weights[v] == consdata->weights[prev] ) 6685 { 6686 /* both variables eliminate themselves: w*x + w*(1-x) == w */ 6687 consdata->capacity -= consdata->weights[v]; 6688 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */ 6689 SCIP_CALL( delCoefPos(scip, cons, prev) ); 6690 6691 --prev; 6692 } 6693 else if( consdata->weights[v] < consdata->weights[prev] ) 6694 { 6695 consdata->capacity -= consdata->weights[v]; 6696 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]); 6697 assert(consdata->weights[prev] > 0); 6698 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */ 6699 } 6700 else 6701 { 6702 consdata->capacity -= consdata->weights[prev]; 6703 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]); 6704 assert(consdata->weights[v] > 0); 6705 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */ 6706 /* restore order iff necessary */ 6707 if( consdata->nvars != v ) /* otherwise the order still stands */ 6708 { 6709 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) ); 6710 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */ 6711 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) ) 6712 --prev; 6713 else /* we need to let v at the same position*/ 6714 { 6715 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */ 6716 /* don't decrease v, the same variable may exist up front */ 6717 --prev; 6718 continue; 6719 } 6720 } 6721 } 6722 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */ 6723 } 6724 v = prev; 6725 --prev; 6726 } 6727 6728 consdata->merged = TRUE; 6729 6730 /* check infeasibility */ 6731 if( consdata->onesweightsum > consdata->capacity ) 6732 { 6733 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n"); 6734 *cutoff = TRUE; 6735 return SCIP_OKAY; 6736 } 6737 6738 return SCIP_OKAY; 6739 } 6740 6741 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the 6742 * fixings (dual reductions) 6743 */ 6744 static 6745 SCIP_RETCODE dualPresolving( 6746 SCIP* scip, /**< SCIP data structure */ 6747 SCIP_CONS* cons, /**< knapsack constraint */ 6748 int* nfixedvars, /**< pointer to count number of fixings */ 6749 int* ndelconss, /**< pointer to count number of deleted constraints */ 6750 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */ 6751 ) 6752 { 6753 SCIP_CONSDATA* consdata; 6754 SCIP_VAR** vars; 6755 SCIP_Real* profits; 6756 int* solitems; 6757 int* nonsolitems; 6758 int* items; 6759 SCIP_Real solval; 6760 SCIP_Bool infeasible; 6761 SCIP_Bool tightened; 6762 SCIP_Bool applicable; 6763 int nsolitems; 6764 int nnonsolitems; 6765 int nvars; 6766 int v; 6767 6768 assert(!SCIPconsIsModifiable(cons)); 6769 6770 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot 6771 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are 6772 * added to the problems have the check flag set to FALSE 6773 */ 6774 if( !SCIPconsIsChecked(cons) ) 6775 return SCIP_OKAY; 6776 6777 consdata = SCIPconsGetData(cons); 6778 assert(consdata != NULL); 6779 6780 nvars = consdata->nvars; 6781 vars = consdata->vars; 6782 6783 SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) ); 6784 SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) ); 6785 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) ); 6786 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) ); 6787 6788 applicable = TRUE; 6789 6790 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint; 6791 * collect object values which are the profits of the knapsack problem 6792 */ 6793 for( v = 0; v < nvars; ++v ) 6794 { 6795 SCIP_VAR* var; 6796 SCIP_Bool negated; 6797 6798 var = vars[v]; 6799 assert(var != NULL); 6800 6801 /* the variable should not be (globally) fixed */ 6802 assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5); 6803 6804 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > 0 6805 || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > 1 ) 6806 { 6807 applicable = FALSE; 6808 break; 6809 } 6810 6811 negated = FALSE; 6812 6813 /* get the active variable */ 6814 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) ); 6815 assert(SCIPvarIsActive(var)); 6816 6817 if( negated ) 6818 profits[v] = SCIPvarGetObj(var); 6819 else 6820 profits[v] = -SCIPvarGetObj(var); 6821 6822 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n", 6823 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]); 6824 items[v] = v; 6825 } 6826 6827 if( applicable ) 6828 { 6829 SCIP_Bool success; 6830 6831 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons)); 6832 SCIPdebugPrintCons(scip, cons, NULL); 6833 6834 /* solve knapsack problem exactly */ 6835 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity, 6836 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) ); 6837 6838 if( success ) 6839 { 6840 SCIP_VAR* var; 6841 6842 /* apply solution of the knapsack as dual reductions */ 6843 for( v = 0; v < nsolitems; ++v ) 6844 { 6845 var = vars[solitems[v]]; 6846 assert(var != NULL); 6847 6848 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n", 6849 SCIPvarGetName(var), SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)); 6850 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) ); 6851 assert(!infeasible); 6852 assert(tightened); 6853 (*nfixedvars)++; 6854 } 6855 6856 for( v = 0; v < nnonsolitems; ++v ) 6857 { 6858 var = vars[nonsolitems[v]]; 6859 assert(var != NULL); 6860 6861 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n", 6862 SCIPvarGetName(var), SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)); 6863 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) ); 6864 assert(!infeasible); 6865 assert(tightened); 6866 (*nfixedvars)++; 6867 } 6868 6869 SCIP_CALL( SCIPdelCons(scip, cons) ); 6870 (*ndelconss)++; 6871 (*deleted) = TRUE; 6872 } 6873 } 6874 6875 SCIPfreeBufferArray(scip, &nonsolitems); 6876 SCIPfreeBufferArray(scip, &solitems); 6877 SCIPfreeBufferArray(scip, &items); 6878 SCIPfreeBufferArray(scip, &profits); 6879 6880 return SCIP_OKAY; 6881 } 6882 6883 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the 6884 * constraint enters the LP by setting the initial and separated flag to FALSE 6885 */ 6886 static 6887 SCIP_RETCODE checkParallelObjective( 6888 SCIP* scip, /**< SCIP data structure */ 6889 SCIP_CONS* cons, /**< knapsack constraint */ 6890 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */ 6891 ) 6892 { 6893 SCIP_CONSDATA* consdata; 6894 SCIP_VAR** vars; 6895 SCIP_VAR* var; 6896 SCIP_Real offset; 6897 SCIP_Real scale; 6898 SCIP_Real objval; 6899 SCIP_Bool applicable; 6900 SCIP_Bool negated; 6901 int nobjvars; 6902 int nvars; 6903 int v; 6904 6905 assert(scip != NULL); 6906 assert(cons != NULL); 6907 assert(conshdlrdata != NULL); 6908 6909 consdata = SCIPconsGetData(cons); 6910 assert(consdata != NULL); 6911 6912 nvars = consdata->nvars; 6913 nobjvars = SCIPgetNObjVars(scip); 6914 6915 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial 6916 * and/or separated flag is set to FALSE 6917 */ 6918 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) ) 6919 return SCIP_OKAY; 6920 6921 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we 6922 * have a pure feasibility problem, we do not want to set a cutoff or lower bound. 6923 */ 6924 if( nobjvars == 0 ) 6925 return SCIP_OKAY; 6926 6927 vars = consdata->vars; 6928 assert(vars != NULL); 6929 6930 applicable = TRUE; 6931 offset = 0.0; 6932 scale = 1.0; 6933 6934 for( v = 0; v < nvars && applicable; ++v ) 6935 { 6936 negated = FALSE; 6937 var = vars[v]; 6938 assert(var != NULL); 6939 6940 if( SCIPvarIsNegated(var) ) 6941 { 6942 negated = TRUE; 6943 var = SCIPvarGetNegatedVar(var); 6944 assert(var != NULL); 6945 } 6946 6947 objval = SCIPvarGetObj(var); 6948 6949 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */ 6950 if( SCIPisZero(scip, objval) ) 6951 applicable = FALSE; 6952 else 6953 { 6954 SCIP_Real weight; 6955 6956 weight = (SCIP_Real)consdata->weights[v]; 6957 6958 if( negated ) 6959 { 6960 if( v == 0 ) 6961 { 6962 /* the first variable defines the scale */ 6963 scale = weight / -objval; 6964 6965 offset += weight; 6966 } 6967 else if( SCIPisEQ(scip, -objval * scale, weight) ) 6968 offset += weight; 6969 else 6970 applicable = FALSE; 6971 } 6972 else if( v == 0 ) 6973 { 6974 /* the first variable define the scale */ 6975 scale = weight / objval; 6976 } 6977 else if( !SCIPisEQ(scip, objval * scale, weight) ) 6978 applicable = FALSE; 6979 } 6980 } 6981 6982 if( applicable ) 6983 { 6984 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound ) 6985 { 6986 SCIP_Real cutoffbound; 6987 6988 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */ 6989 SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) ); 6990 SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) ); 6991 6992 cutoffbound = (consdata->capacity - offset) / scale; 6993 6994 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n", 6995 SCIPconsGetName(cons), cutoffbound); 6996 6997 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are 6998 * still excepted 6999 */ 7000 cutoffbound += SCIPcutoffbounddelta(scip); 7001 7002 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n", 7003 SCIPconsGetName(cons), cutoffbound); 7004 7005 if( cutoffbound < SCIPgetCutoffbound(scip) ) 7006 { 7007 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound); 7008 7009 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) ); 7010 } 7011 else 7012 { 7013 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and 7014 * propagation 7015 */ 7016 SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) ); 7017 SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) ); 7018 } 7019 } 7020 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound ) 7021 { 7022 SCIP_Real lowerbound; 7023 7024 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */ 7025 SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) ); 7026 SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) ); 7027 7028 lowerbound = (consdata->capacity - offset) / scale; 7029 7030 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n", 7031 SCIPconsGetName(cons), lowerbound); 7032 7033 SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) ); 7034 } 7035 } 7036 7037 return SCIP_OKAY; 7038 } 7039 7040 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a 7041 * weight of one variable is greater or equal another weight and both variables are in the same cliques */ 7042 static 7043 SCIP_RETCODE stableSort( 7044 SCIP* scip, /**< SCIP data structure */ 7045 SCIP_CONSDATA* consdata, /**< knapsack constraint data */ 7046 SCIP_VAR** vars, /**< array for sorted variables */ 7047 SCIP_Longint* weights, /**< array for sorted weights */ 7048 int* cliquestartposs, /**< starting position array for each clique */ 7049 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */ 7050 ) 7051 { 7052 SCIP_VAR** origvars; 7053 int norigvars; 7054 SCIP_Longint* origweights; 7055 int* cliquepartition; 7056 int ncliques; 7057 7058 SCIP_VAR*** varpointers; 7059 SCIP_Longint** weightpointers; 7060 int* cliquecount; 7061 7062 int nextpos; 7063 int c; 7064 int v; 7065 7066 assert(scip != NULL); 7067 assert(consdata != NULL); 7068 assert(vars != NULL); 7069 assert(weights != NULL); 7070 assert(cliquestartposs != NULL); 7071 7072 origweights = consdata->weights; 7073 origvars = consdata->vars; 7074 norigvars = consdata->nvars; 7075 7076 assert(origvars != NULL || norigvars == 0); 7077 assert(origweights != NULL || norigvars == 0); 7078 7079 if( norigvars == 0 ) 7080 return SCIP_OKAY; 7081 7082 if( usenegatedclique ) 7083 { 7084 assert(consdata->negcliquepartitioned); 7085 7086 cliquepartition = consdata->negcliquepartition; 7087 ncliques = consdata->nnegcliques; 7088 } 7089 else 7090 { 7091 assert(consdata->cliquepartitioned); 7092 7093 cliquepartition = consdata->cliquepartition; 7094 ncliques = consdata->ncliques; 7095 } 7096 7097 assert(cliquepartition != NULL); 7098 assert(ncliques > 0); 7099 7100 /* we first count all clique items and alloc temporary memory for a bucket sort */ 7101 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) ); 7102 BMSclearMemoryArray(cliquecount, ncliques); 7103 7104 /* first we count for each clique the number of elements */ 7105 for( v = norigvars - 1; v >= 0; --v ) 7106 { 7107 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques); 7108 ++(cliquecount[cliquepartition[v]]); 7109 } 7110 7111 /*@todo: maybe it is better to put largest cliques up front */ 7112 7113 #ifndef NDEBUG 7114 BMSclearMemoryArray(vars, norigvars); 7115 BMSclearMemoryArray(weights, norigvars); 7116 #endif 7117 SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) ); 7118 SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) ); 7119 7120 nextpos = 0; 7121 /* now we initialize all start pointers for each clique, so they will be ordered */ 7122 for( c = 0; c < ncliques; ++c ) 7123 { 7124 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the 7125 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer 7126 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer 7127 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be 7128 * vars[7] 7129 * 7130 */ 7131 varpointers[c] = (SCIP_VAR**) (vars + nextpos); 7132 cliquestartposs[c] = nextpos; 7133 weightpointers[c] = (SCIP_Longint*) (weights + nextpos); 7134 assert(cliquecount[c] > 0); 7135 nextpos += cliquecount[c]; 7136 assert(nextpos > 0); 7137 } 7138 assert(nextpos == norigvars); 7139 cliquestartposs[c] = nextpos; 7140 7141 /* now we copy all variable and weights to the right order */ 7142 for( v = 0; v < norigvars; ++v ) 7143 { 7144 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/ 7145 ++(varpointers[cliquepartition[v]]); 7146 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/ 7147 ++(weightpointers[cliquepartition[v]]); 7148 } 7149 #ifndef NDEBUG 7150 for( v = 0; v < norigvars; ++v ) 7151 { 7152 assert(vars[v] != NULL); 7153 assert(weights[v] > 0); 7154 } 7155 #endif 7156 7157 /* free temporary memory */ 7158 SCIPfreeBufferArray(scip, &weightpointers); 7159 SCIPfreeBufferArray(scip, &varpointers); 7160 SCIPfreeBufferArray(scip, &cliquecount); 7161 7162 return SCIP_OKAY; 7163 } 7164 7165 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */ 7166 static 7167 SCIP_RETCODE applyFixings( 7168 SCIP* scip, /**< SCIP data structure */ 7169 SCIP_CONS* cons, /**< knapsack constraint */ 7170 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this 7171 * information is not needed; in this case, we apply all fixings 7172 * instead of stopping after the first infeasible one */ 7173 ) 7174 { 7175 SCIP_CONSDATA* consdata; 7176 int v; 7177 7178 assert(scip != NULL); 7179 assert(cons != NULL); 7180 7181 consdata = SCIPconsGetData(cons); 7182 assert(consdata != NULL); 7183 assert(consdata->nvars == 0 || consdata->vars != NULL); 7184 7185 if( cutoff != NULL ) 7186 *cutoff = FALSE; 7187 7188 SCIPdebugMsg(scip, "apply fixings:\n"); 7189 SCIPdebugPrintCons(scip, cons, NULL); 7190 7191 /* check infeasibility */ 7192 if ( consdata->onesweightsum > consdata->capacity ) 7193 { 7194 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n"); 7195 7196 if( cutoff != NULL ) 7197 *cutoff = TRUE; 7198 7199 return SCIP_OKAY; 7200 } 7201 7202 /* all multi-aggregations should be resolved */ 7203 consdata->existmultaggr = FALSE; 7204 7205 v = 0; 7206 while( v < consdata->nvars ) 7207 { 7208 SCIP_VAR* var; 7209 7210 var = consdata->vars[v]; 7211 assert(SCIPvarIsBinary(var)); 7212 7213 if( SCIPvarGetLbGlobal(var) > 0.5 ) 7214 { 7215 assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0)); 7216 consdata->capacity -= consdata->weights[v]; 7217 SCIP_CALL( delCoefPos(scip, cons, v) ); 7218 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */ 7219 } 7220 else if( SCIPvarGetUbGlobal(var) < 0.5 ) 7221 { 7222 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0)); 7223 SCIP_CALL( delCoefPos(scip, cons, v) ); 7224 } 7225 else 7226 { 7227 SCIP_VAR* repvar; 7228 SCIP_VAR* negvar; 7229 SCIP_VAR* workvar; 7230 SCIP_Longint weight; 7231 SCIP_Bool negated; 7232 7233 weight = consdata->weights[v]; 7234 7235 /* get binary representative of variable */ 7236 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) ); 7237 assert(repvar != NULL); 7238 7239 /* check for multi-aggregation */ 7240 if( SCIPvarIsNegated(repvar) ) 7241 { 7242 workvar = SCIPvarGetNegatedVar(repvar); 7243 assert(workvar != NULL); 7244 negated = TRUE; 7245 } 7246 else 7247 { 7248 workvar = repvar; 7249 negated = FALSE; 7250 } 7251 7252 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack 7253 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary 7254 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity 7255 * 7256 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means, 7257 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c) 7258 * 7259 * The explanation for the following block: 7260 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by 7261 * weight * (a_1*y_1 + ... + a_n*y_n + c). 7262 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by 7263 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight 7264 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c). 7265 * 2) For all replacement variable we check: 7266 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through 7267 * capacity -= weight * a_i caused by the negation of y_i. 7268 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint. 7269 * 3a) If repvar was not negated we need to subtract weight * c from capacity. 7270 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of 7271 * weight in this case. 7272 */ 7273 if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR ) 7274 { 7275 SCIP_VAR** aggrvars; 7276 SCIP_Real* aggrscalars; 7277 SCIP_Real aggrconst; 7278 int naggrvars; 7279 int i; 7280 7281 SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) ); 7282 naggrvars = SCIPvarGetMultaggrNVars(workvar); 7283 aggrvars = SCIPvarGetMultaggrVars(workvar); 7284 aggrscalars = SCIPvarGetMultaggrScalars(workvar); 7285 aggrconst = SCIPvarGetMultaggrConstant(workvar); 7286 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0); 7287 7288 if( !SCIPisIntegral(scip, weight * aggrconst) ) 7289 { 7290 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst); 7291 return SCIP_ERROR; 7292 } 7293 7294 /* if workvar was negated, we have to flip the weight */ 7295 if( negated ) 7296 weight *= -1; 7297 7298 for( i = naggrvars - 1; i >= 0; --i ) 7299 { 7300 assert(aggrvars != NULL); 7301 assert(aggrscalars != NULL); 7302 7303 if( !SCIPvarIsBinary(aggrvars[i]) ) 7304 { 7305 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n", 7306 SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i])); 7307 return SCIP_ERROR; 7308 } 7309 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) ) 7310 { 7311 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]); 7312 return SCIP_ERROR; 7313 } 7314 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */ 7315 if( SCIPisNegative(scip, weight * aggrscalars[i]) ) 7316 { 7317 SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar)); 7318 assert(negvar != NULL); 7319 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) ); 7320 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5)); 7321 } 7322 else 7323 { 7324 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) ); 7325 } 7326 } 7327 /* delete old coefficient */ 7328 SCIP_CALL( delCoefPos(scip, cons, v) ); 7329 7330 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */ 7331 if( negated ) 7332 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5); 7333 else 7334 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5); 7335 7336 if( consdata->capacity < 0 ) 7337 { 7338 if( cutoff != NULL ) 7339 { 7340 *cutoff = TRUE; 7341 break; 7342 } 7343 } 7344 } 7345 /* check, if the variable should be replaced with the representative */ 7346 else if( repvar != var ) 7347 { 7348 /* delete old (aggregated) variable */ 7349 SCIP_CALL( delCoefPos(scip, cons, v) ); 7350 7351 /* add representative instead */ 7352 SCIP_CALL( addCoef(scip, cons, repvar, weight) ); 7353 } 7354 else 7355 ++v; 7356 } 7357 } 7358 assert(consdata->onesweightsum == 0); 7359 7360 SCIPdebugMsg(scip, "after applyFixings, before merging:\n"); 7361 SCIPdebugPrintCons(scip, cons, NULL); 7362 7363 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to 7364 * clean up the constraint 7365 */ 7366 if( cutoff != NULL && !(*cutoff) ) 7367 { 7368 SCIP_CALL( mergeMultiples(scip, cons, cutoff) ); 7369 SCIPdebugMsg(scip, "after applyFixings and merging:\n"); 7370 SCIPdebugPrintCons(scip, cons, NULL); 7371 } 7372 7373 return SCIP_OKAY; 7374 } 7375 7376 7377 /** propagation method for knapsack constraints */ 7378 static 7379 SCIP_RETCODE propagateCons( 7380 SCIP* scip, /**< SCIP data structure */ 7381 SCIP_CONS* cons, /**< knapsack constraint */ 7382 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */ 7383 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */ 7384 int* nfixedvars, /**< pointer to count number of fixings */ 7385 SCIP_Bool usenegatedclique /**< should negated clique information be used */ 7386 ) 7387 { 7388 SCIP_CONSDATA* consdata; 7389 SCIP_Bool infeasible; 7390 SCIP_Bool tightened; 7391 SCIP_Longint* secondmaxweights; 7392 SCIP_Longint minweightsum; 7393 SCIP_Longint residualcapacity; 7394 7395 int nvars; 7396 int i; 7397 int nnegcliques; 7398 7399 SCIP_VAR** myvars; 7400 SCIP_Longint* myweights; 7401 int* cliquestartposs; 7402 int* cliqueendposs; 7403 SCIP_Longint localminweightsum; 7404 SCIP_Bool foundmax; 7405 int c; 7406 7407 assert(scip != NULL); 7408 assert(cons != NULL); 7409 assert(cutoff != NULL); 7410 assert(redundant != NULL); 7411 assert(nfixedvars != NULL); 7412 7413 consdata = SCIPconsGetData(cons); 7414 assert(consdata != NULL); 7415 7416 *cutoff = FALSE; 7417 *redundant = FALSE; 7418 7419 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons)); 7420 7421 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */ 7422 if( !SCIPinRepropagation(scip) ) 7423 { 7424 SCIP_CALL( SCIPincConsAge(scip, cons) ); 7425 } 7426 7427 #ifndef NDEBUG 7428 /* assert that only active or negated variables are present */ 7429 for( i = 0; i < consdata->nvars && consdata->merged; ++i ) 7430 { 7431 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED); 7432 } 7433 #endif 7434 7435 usenegatedclique = usenegatedclique && consdata->merged; 7436 7437 /* init for debugging */ 7438 myvars = NULL; 7439 myweights = NULL; 7440 cliquestartposs = NULL; 7441 secondmaxweights = NULL; 7442 minweightsum = 0; 7443 nvars = consdata->nvars; 7444 /* make sure, the items are sorted by non-increasing weight */ 7445 sortItems(consdata); 7446 7447 do 7448 { 7449 localminweightsum = 0; 7450 7451 /* (1) compute the minimum weight of the knapsack constraint using negated clique information; 7452 * a negated clique means, that at most one of the clique variables can be zero 7453 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C 7454 * 7455 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1 7456 * since replacing i with the element of maximal weight leads to infeasibility 7457 */ 7458 if( usenegatedclique && nvars > 0 ) 7459 { 7460 SCIP_CONSHDLRDATA* conshdlrdata; 7461 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons)); 7462 assert(conshdlrdata != NULL); 7463 7464 /* compute clique partitions */ 7465 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) ); 7466 nnegcliques = consdata->nnegcliques; 7467 7468 /* if we have no real negated cliques we can stop here */ 7469 if( nnegcliques == nvars ) 7470 { 7471 /* run the standard algorithm that does not involve cliques */ 7472 usenegatedclique = FALSE; 7473 break; 7474 } 7475 7476 /* allocate temporary memory and initialize it */ 7477 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) ); 7478 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ; 7479 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) ); 7480 SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) ); 7481 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) ); 7482 BMSclearMemoryArray(secondmaxweights, nnegcliques); 7483 7484 /* resort variables to avoid quadratic algorithm later on */ 7485 SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) ); 7486 7487 /* save the end positions of the cliques because start positions are moved in the following loop */ 7488 for( c = 0; c < nnegcliques; ++c ) 7489 { 7490 cliqueendposs[c] = cliquestartposs[c+1] - 1; 7491 assert(cliqueendposs[c] - cliquestartposs[c] >= 0); 7492 } 7493 7494 c = 0; 7495 foundmax = FALSE; 7496 i = 0; 7497 7498 while( i < nvars ) 7499 { 7500 /* ignore variables of the negated clique which are fixed to one since these are counted in 7501 * consdata->onesweightsum 7502 */ 7503 7504 /* if there are only one variable negated cliques left we can stop */ 7505 if( nnegcliques - c == nvars - i ) 7506 { 7507 minweightsum += localminweightsum; 7508 localminweightsum = 0; 7509 break; 7510 } 7511 7512 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each 7513 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all 7514 * other clique variables to one 7515 */ 7516 if( cliquestartposs[c] == i ) 7517 { 7518 assert(myweights[i] > 0); 7519 ++c; 7520 minweightsum += localminweightsum; 7521 localminweightsum = 0; 7522 foundmax = TRUE; 7523 7524 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 ) 7525 foundmax = FALSE; 7526 7527 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 ) 7528 { 7529 ++i; 7530 continue; 7531 } 7532 } 7533 7534 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 ) 7535 { 7536 assert(myweights[i] > 0); 7537 7538 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 ) 7539 { 7540 assert(myweights[i] <= myweights[cliquestartposs[c - 1]]); 7541 7542 if( !foundmax ) 7543 { 7544 foundmax = TRUE; 7545 7546 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */ 7547 cliquestartposs[c - 1] = i; 7548 ++i; 7549 7550 continue; 7551 } 7552 /* memorize second max weight for each clique */ 7553 if( secondmaxweights[c - 1] == 0 ) 7554 secondmaxweights[c - 1] = myweights[i]; 7555 7556 localminweightsum += myweights[i]; 7557 } 7558 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */ 7559 else 7560 { 7561 int v; 7562 /* fix all other variables of the negated clique to 1 */ 7563 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v ) 7564 { 7565 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 ) 7566 { 7567 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v])); 7568 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) ); 7569 7570 if( infeasible ) 7571 { 7572 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 ); 7573 7574 /* analyze the infeasibility if conflict analysis is applicable */ 7575 if( SCIPisConflictAnalysisApplicable(scip) ) 7576 { 7577 /* conflict analysis can only be applied in solving stage */ 7578 assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip)); 7579 7580 /* initialize the conflict analysis */ 7581 SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) ); 7582 7583 /* add the two variables which are fixed to zero within a negated clique */ 7584 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) ); 7585 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) ); 7586 7587 /* start the conflict analysis */ 7588 SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) ); 7589 } 7590 *cutoff = TRUE; 7591 break; 7592 } 7593 assert(tightened); 7594 ++(*nfixedvars); 7595 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 7596 } 7597 } 7598 7599 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */ 7600 localminweightsum = 0; 7601 /* we can jump to the end of this clique */ 7602 i = cliqueendposs[c - 1]; 7603 7604 if( *cutoff ) 7605 break; 7606 } 7607 } 7608 ++i; 7609 } 7610 /* add last clique minweightsum */ 7611 minweightsum += localminweightsum; 7612 7613 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n", 7614 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum ); 7615 7616 /* check, if weights of fixed variables don't exceeds knapsack capacity */ 7617 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum ) 7618 { 7619 SCIP_Longint maxcliqueweight = -1LL; 7620 7621 /* loop over cliques */ 7622 for( c = 0; c < nnegcliques; ++c ) 7623 { 7624 SCIP_VAR* maxvar; 7625 SCIP_Bool maxvarfixed; 7626 int endvarposclique; 7627 int startvarposclique; 7628 7629 assert(myvars != NULL); 7630 assert(nnegcliques == consdata->nnegcliques); 7631 assert(myweights != NULL); 7632 assert(secondmaxweights != NULL); 7633 assert(cliquestartposs != NULL); 7634 7635 endvarposclique = cliqueendposs[c]; 7636 startvarposclique = cliquestartposs[c]; 7637 7638 maxvar = myvars[startvarposclique]; 7639 7640 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */ 7641 if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 ) 7642 continue; 7643 7644 maxcliqueweight = myweights[startvarposclique]; 7645 maxvarfixed = FALSE; 7646 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already 7647 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique 7648 * exceeds the capacity the maximum weight variable can be fixed to zero. 7649 */ 7650 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity ) 7651 { 7652 #ifndef NDEBUG 7653 SCIP_Longint oldonesweightsum = consdata->onesweightsum; 7654 #endif 7655 assert(maxcliqueweight >= secondmaxweights[c]); 7656 assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5); 7657 7658 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar)); 7659 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 7660 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) ); 7661 assert(consdata->onesweightsum == oldonesweightsum); 7662 assert(!infeasible); 7663 assert(tightened); 7664 (*nfixedvars)++; 7665 maxvarfixed = TRUE; 7666 } 7667 /* the remaining cliques are singletons such that all subsequent variables have a weight that 7668 * fits into the knapsack 7669 */ 7670 else if( nnegcliques - c == nvars - startvarposclique ) 7671 break; 7672 /* early termination of the remaining loop because no further variable fixings are possible: 7673 * 7674 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second 7675 * largest was set to 0) does not suffice to infer additional variable fixings because 7676 * 7677 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight 7678 * - their second largest elements are at least as large as the smallest weight of the knapsack 7679 */ 7680 else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity ) 7681 break; 7682 7683 /* loop over items with non-maximal weight (omitting the first position) */ 7684 for( i = endvarposclique; i > startvarposclique; --i ) 7685 { 7686 /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we 7687 * messed up the clique preprocessing in the previous loop to filter those variables out */ 7688 assert(SCIPvarGetUbLocal(myvars[i]) > 0.5); 7689 7690 /* only check variables of negated cliques for which no variable is locally fixed */ 7691 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 ) 7692 { 7693 assert(maxcliqueweight >= myweights[i]); 7694 assert(i == endvarposclique || myweights[i] >= myweights[i+1]); 7695 7696 /* we fix the members of this clique with non-maximal weight in two cases to 1: 7697 * 7698 * the maxvar was already fixed to 0 because it has a huge gain. 7699 * 7700 * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1 7701 * since replacing i with the element of maximal weight leads to infeasibility */ 7702 if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity ) 7703 { 7704 #ifndef NDEBUG 7705 SCIP_Longint oldonesweightsum = consdata->onesweightsum; 7706 #endif 7707 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i])); 7708 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) ); 7709 assert(consdata->onesweightsum == oldonesweightsum + myweights[i]); 7710 assert(!infeasible); 7711 assert(tightened); 7712 ++(*nfixedvars); 7713 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 7714 7715 /* update minweightsum because now the variable is fixed to one and its weight is counted by 7716 * consdata->onesweightsum 7717 */ 7718 minweightsum -= myweights[i]; 7719 assert(minweightsum >= 0); 7720 } 7721 else 7722 break; 7723 } 7724 } 7725 #ifndef NDEBUG 7726 /* in debug mode, we assert that we did not miss possible fixings by the break above */ 7727 for( ; i > startvarposclique; --i ) 7728 { 7729 SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5; 7730 SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity; 7731 7732 assert(i == endvarposclique || myweights[i] >= myweights[i+1]); 7733 assert(varisfixed || !exceedscapacity); 7734 } 7735 #endif 7736 } 7737 } 7738 SCIPfreeBufferArray(scip, &secondmaxweights); 7739 SCIPfreeBufferArray(scip, &cliqueendposs); 7740 SCIPfreeBufferArray(scip, &cliquestartposs); 7741 SCIPfreeBufferArray(scip, &myweights); 7742 SCIPfreeBufferArray(scip, &myvars); 7743 } 7744 7745 assert(consdata->negcliquepartitioned || minweightsum == 0); 7746 } 7747 while( FALSE ); 7748 7749 assert(usenegatedclique || minweightsum == 0); 7750 /* check, if weights of fixed variables already exceed knapsack capacity */ 7751 if( consdata->capacity < minweightsum + consdata->onesweightsum ) 7752 { 7753 SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n", 7754 consdata->onesweightsum, consdata->capacity); 7755 7756 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 7757 *cutoff = TRUE; 7758 7759 /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */ 7760 if( (SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip)) && SCIPisConflictAnalysisApplicable(scip) ) 7761 { 7762 /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */ 7763 SCIP_Longint weight; 7764 7765 weight = 0; 7766 7767 SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) ); 7768 7769 for( i = 0; i < nvars && weight <= consdata->capacity; i++ ) 7770 { 7771 if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5) 7772 { 7773 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) ); 7774 weight += consdata->weights[i]; 7775 } 7776 } 7777 7778 SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) ); 7779 } 7780 7781 return SCIP_OKAY; 7782 } 7783 7784 /* the algorithm below is a special case of propagation involving negated cliques */ 7785 if( !usenegatedclique ) 7786 { 7787 assert(consdata->sorted); 7788 residualcapacity = consdata->capacity - consdata->onesweightsum; 7789 7790 /* fix all variables to zero, that don't fit into the knapsack anymore */ 7791 for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i ) 7792 { 7793 /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed 7794 * to zero 7795 */ 7796 if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 ) 7797 { 7798 if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 ) 7799 { 7800 assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity); 7801 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i])); 7802 SCIP_CALL( SCIPresetConsAge(scip, cons) ); 7803 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) ); 7804 assert(!infeasible); 7805 assert(tightened); 7806 (*nfixedvars)++; 7807 } 7808 } 7809 } 7810 } 7811 7812 /* check if the knapsack is now redundant */ 7813 if( !SCIPconsIsModifiable(cons) ) 7814 { 7815 SCIP_Longint unfixedweightsum = consdata->onesweightsum; 7816 7817 /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */ 7818 for( i = 0; i < nvars; ++i ) 7819 { 7820 if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) ) 7821 { 7822 unfixedweightsum += consdata->weights[i]; 7823 7824 /* the weight sum is larger than the capacity, so the constraint is not redundant */ 7825 if( unfixedweightsum > consdata->capacity ) 7826 return SCIP_OKAY; 7827 } 7828 } 7829 /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */ 7830 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n", 7831 SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity); 7832 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 7833 *redundant = TRUE; 7834 } 7835 7836 return SCIP_OKAY; 7837 } 7838 7839 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint 7840 * containing all negated variables of this knapsack constraint 7841 */ 7842 static 7843 SCIP_RETCODE upgradeCons( 7844 SCIP* scip, /**< SCIP data structure */ 7845 SCIP_CONS* cons, /**< knapsack constraint */ 7846 int* ndelconss, /**< pointer to store the amount of deleted constraints */ 7847 int* naddconss /**< pointer to count number of added constraints */ 7848 ) 7849 { 7850 SCIP_CONS* newcons; 7851 SCIP_CONSDATA* consdata; 7852 7853 assert(scip != NULL); 7854 assert(cons != NULL); 7855 assert(ndelconss != NULL); 7856 assert(naddconss != NULL); 7857 7858 consdata = SCIPconsGetData(cons); 7859 assert(consdata != NULL); 7860 assert(consdata->nvars > 1); 7861 7862 /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */ 7863 if( consdata->nvars == 2 ) 7864 { 7865 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons)); 7866 7867 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars, 7868 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 7869 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 7870 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), 7871 SCIPconsIsStickingAtNode(cons)) ); 7872 } 7873 /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint 7874 * containing all negated variables of the knapsack 7875 */ 7876 else 7877 { 7878 SCIP_VAR** consvars; 7879 7880 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons)); 7881 7882 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) ); 7883 SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) ); 7884 7885 SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars, 7886 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 7887 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 7888 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), 7889 SCIPconsIsStickingAtNode(cons)) ); 7890 7891 SCIPfreeBufferArray(scip, &consvars); 7892 } 7893 7894 SCIP_CALL( SCIPaddCons(scip, newcons) ); 7895 SCIP_CALL( SCIPreleaseCons(scip, &newcons) ); 7896 ++(*naddconss); 7897 7898 SCIP_CALL( SCIPdelCons(scip, cons) ); 7899 ++(*ndelconss); 7900 7901 return SCIP_OKAY; 7902 } 7903 7904 /** delete redundant variables 7905 * 7906 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them 7907 * 7908 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique 7909 * => x4, x5 always fits into the knapsack, so we can delete them 7910 * 7911 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too 7912 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack 7913 */ 7914 static 7915 SCIP_RETCODE deleteRedundantVars( 7916 SCIP* scip, /**< SCIP data structure */ 7917 SCIP_CONS* cons, /**< knapsack constraint */ 7918 SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */ 7919 int splitpos, /**< split position till when all front items are fitting, splitpos is the 7920 * first which did not fit */ 7921 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */ 7922 int* nchgsides, /**< pointer to store the amount of changed sides */ 7923 int* naddconss /**< pointer to count number of added constraints */ 7924 ) 7925 { 7926 SCIP_CONSHDLRDATA* conshdlrdata; 7927 SCIP_CONSDATA* consdata; 7928 SCIP_VAR** vars; 7929 SCIP_Longint* weights; 7930 SCIP_Longint capacity; 7931 SCIP_Longint gcd; 7932 int nvars; 7933 int w; 7934 7935 assert(scip != NULL); 7936 assert(cons != NULL); 7937 assert(nchgcoefs != NULL); 7938 assert(nchgsides != NULL); 7939 assert(naddconss != NULL); 7940 7941 consdata = SCIPconsGetData(cons); 7942 assert(consdata != NULL); 7943 assert(0 < frontsum && frontsum < consdata->weightsum); 7944 assert(0 < splitpos && splitpos < consdata->nvars); 7945 7946 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons)); 7947 assert(conshdlrdata != NULL); 7948 7949 vars = consdata->vars; 7950 weights = consdata->weights; 7951 nvars = consdata->nvars; 7952 capacity = consdata->capacity; 7953 7954 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal 7955 * weight must not be sorted by their index 7956 */ 7957 #ifndef NDEBUG 7958 for( w = nvars - 1; w > 0; --w ) 7959 assert(weights[w] <= weights[w-1]); 7960 #endif 7961 7962 /* if there are no variables rear to splitpos, the constraint has no redundant variables */ 7963 if( consdata->nvars - 1 == splitpos ) 7964 return SCIP_OKAY; 7965 7966 assert(frontsum + weights[splitpos] > capacity); 7967 7968 /* detect redundant variables */ 7969 if( consdata->weightsum - weights[splitpos] <= capacity ) 7970 { 7971 /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always 7972 * fit 7973 */ 7974 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons)); 7975 7976 /* delete items and update capacity */ 7977 for( w = nvars - 1; w > splitpos; --w ) 7978 { 7979 consdata->capacity -= weights[w]; 7980 SCIP_CALL( delCoefPos(scip, cons, w) ); 7981 } 7982 assert(w == splitpos); 7983 7984 ++(*nchgsides); 7985 *nchgcoefs += (nvars - splitpos); 7986 7987 /* division by greatest common divisor */ 7988 gcd = weights[w]; 7989 for( ; w >= 0 && gcd > 1; --w ) 7990 { 7991 gcd = SCIPcalcGreComDiv(gcd, weights[w]); 7992 } 7993 7994 /* normalize if possible */ 7995 if( gcd > 1 ) 7996 { 7997 for( w = splitpos; w >= 0; --w ) 7998 { 7999 consdataChgWeight(consdata, w, weights[w]/gcd); 8000 } 8001 (*nchgcoefs) += nvars; 8002 8003 consdata->capacity /= gcd; 8004 ++(*nchgsides); 8005 } 8006 8007 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal 8008 * weight must not be sorted by their index 8009 */ 8010 #ifndef NDEBUG 8011 for( w = consdata->nvars - 1; w > 0; --w ) 8012 assert(weights[w] <= weights[w - 1]); 8013 #endif 8014 } 8015 /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would 8016 * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at 8017 * splitpos and needs to fit into the knapsack 8018 */ 8019 else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity ) 8020 { 8021 int* clqpart; 8022 int nclq; 8023 int len; 8024 8025 len = nvars - (splitpos + 1); 8026 /* allocate temporary memory */ 8027 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) ); 8028 8029 /* calculate clique partition */ 8030 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) ); 8031 8032 /* check if we found at least one clique */ 8033 if( nclq < len ) 8034 { 8035 SCIP_Longint maxactduetoclq; 8036 int cliquenum; 8037 8038 maxactduetoclq = 0; 8039 cliquenum = 0; 8040 8041 /* calculate maximum activity due to cliques */ 8042 for( w = 0; w < len; ++w ) 8043 { 8044 assert(clqpart[w] >= 0 && clqpart[w] <= w); 8045 if( clqpart[w] == cliquenum ) 8046 { 8047 maxactduetoclq += weights[w + splitpos + 1]; 8048 ++cliquenum; 8049 } 8050 } 8051 8052 /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before, 8053 * so delete them and create for all clique the corresponding clique constraints and update the capacity 8054 */ 8055 if( frontsum + maxactduetoclq <= capacity ) 8056 { 8057 SCIP_VAR** clqvars; 8058 int nclqvars; 8059 int c; 8060 8061 assert(maxactduetoclq < weights[splitpos]); 8062 8063 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons)); 8064 8065 /* allocate temporary memory */ 8066 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) ); 8067 8068 for( c = 0; c < nclq; ++c ) 8069 { 8070 nclqvars = 0; 8071 for( w = 0; w < len; ++w ) 8072 { 8073 if( clqpart[w] == c ) 8074 { 8075 clqvars[nclqvars] = vars[w + splitpos + 1]; 8076 ++nclqvars; 8077 } 8078 } 8079 8080 /* we found a real clique so extract this constraint, because we do not know who this information generated so */ 8081 if( nclqvars > 1 ) 8082 { 8083 SCIP_CONS* cliquecons; 8084 char name[SCIP_MAXSTRLEN]; 8085 8086 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c); 8087 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars, 8088 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 8089 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 8090 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), 8091 SCIPconsIsStickingAtNode(cons)) ); 8092 SCIPdebugMsg(scip, " -> adding clique constraint: "); 8093 SCIPdebugPrintCons(scip, cliquecons, NULL); 8094 SCIP_CALL( SCIPaddCons(scip, cliquecons) ); 8095 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) ); 8096 ++(*naddconss); 8097 } 8098 } 8099 8100 /* delete items and update capacity */ 8101 for( w = nvars - 1; w > splitpos; --w ) 8102 { 8103 SCIP_CALL( delCoefPos(scip, cons, w) ); 8104 ++(*nchgcoefs); 8105 } 8106 consdata->capacity -= maxactduetoclq; 8107 assert(frontsum <= consdata->capacity); 8108 ++(*nchgsides); 8109 8110 assert(w == splitpos); 8111 8112 /* renew weights pointer */ 8113 weights = consdata->weights; 8114 8115 /* division by greatest common divisor */ 8116 gcd = weights[w]; 8117 for( ; w >= 0 && gcd > 1; --w ) 8118 { 8119 gcd = SCIPcalcGreComDiv(gcd, weights[w]); 8120 } 8121 8122 /* normalize if possible */ 8123 if( gcd > 1 ) 8124 { 8125 for( w = splitpos; w >= 0; --w ) 8126 { 8127 consdataChgWeight(consdata, w, weights[w]/gcd); 8128 } 8129 (*nchgcoefs) += nvars; 8130 8131 consdata->capacity /= gcd; 8132 ++(*nchgsides); 8133 } 8134 8135 /* free temporary memory */ 8136 SCIPfreeBufferArray(scip, &clqvars); 8137 8138 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal 8139 * weight must not be sorted by their index 8140 */ 8141 #ifndef NDEBUG 8142 for( w = consdata->nvars - 1; w > 0; --w ) 8143 assert(weights[w] <= weights[w - 1]); 8144 #endif 8145 } 8146 } 8147 8148 /* free temporary memory */ 8149 SCIPfreeBufferArray(scip, &clqpart); 8150 } 8151 8152 return SCIP_OKAY; 8153 } 8154 8155 /* detect redundant variables which always fits into the knapsack 8156 * 8157 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them 8158 * 8159 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique 8160 * => x4, x5 always fits into the knapsack, so we can delete them 8161 * 8162 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too 8163 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack 8164 */ 8165 static 8166 SCIP_RETCODE detectRedundantVars( 8167 SCIP* scip, /**< SCIP data structure */ 8168 SCIP_CONS* cons, /**< knapsack constraint */ 8169 int* ndelconss, /**< pointer to store the amount of deleted constraints */ 8170 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */ 8171 int* nchgsides, /**< pointer to store the amount of changed sides */ 8172 int* naddconss /**< pointer to count number of added constraints */ 8173 ) 8174 { 8175 SCIP_CONSHDLRDATA* conshdlrdata; 8176 SCIP_CONSDATA* consdata; 8177 SCIP_VAR** vars; 8178 SCIP_Longint* weights; 8179 SCIP_Longint capacity; 8180 SCIP_Longint sum; 8181 int noldchgcoefs; 8182 int nvars; 8183 int v; 8184 int w; 8185 8186 assert(scip != NULL); 8187 assert(cons != NULL); 8188 assert(ndelconss != NULL); 8189 assert(nchgcoefs != NULL); 8190 assert(nchgsides != NULL); 8191 assert(naddconss != NULL); 8192 8193 consdata = SCIPconsGetData(cons); 8194 assert(consdata != NULL); 8195 assert(consdata->nvars >= 2); 8196 assert(consdata->weightsum > consdata->capacity); 8197 8198 noldchgcoefs = *nchgcoefs; 8199 vars = consdata->vars; 8200 weights = consdata->weights; 8201 nvars = consdata->nvars; 8202 capacity = consdata->capacity; 8203 sum = 0; 8204 8205 /* search for maximal fitting items */ 8206 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v ) 8207 sum += weights[v]; 8208 8209 assert(v < nvars); 8210 8211 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */ 8212 if( v == nvars - 1 ) 8213 { 8214 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) ); 8215 assert(SCIPconsIsDeleted(cons)); 8216 8217 return SCIP_OKAY; 8218 } 8219 8220 if( v < nvars - 1 ) 8221 { 8222 /* try to delete variables */ 8223 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) ); 8224 assert(consdata->nvars > 1); 8225 8226 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */ 8227 if( v == consdata->nvars - 1 ) 8228 { 8229 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) ); 8230 assert(SCIPconsIsDeleted(cons)); 8231 } 8232 8233 return SCIP_OKAY; 8234 } 8235 8236 /* if we already found some redundant variables, stop here */ 8237 if( *nchgcoefs > noldchgcoefs ) 8238 return SCIP_OKAY; 8239 8240 assert(vars == consdata->vars); 8241 assert(weights == consdata->weights); 8242 assert(nvars == consdata->nvars); 8243 assert(capacity == consdata->capacity); 8244 8245 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons)); 8246 assert(conshdlrdata != NULL); 8247 /* calculate clique partition */ 8248 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) ); 8249 8250 /* check for real existing cliques */ 8251 if( consdata->cliquepartition[v] < v ) 8252 { 8253 SCIP_Longint sumfront; 8254 SCIP_Longint maxactduetoclqfront; 8255 int* clqpart; 8256 int cliquenum; 8257 8258 sumfront = 0; 8259 maxactduetoclqfront = 0; 8260 8261 clqpart = consdata->cliquepartition; 8262 cliquenum = 0; 8263 8264 /* calculate maximal activity due to cliques */ 8265 for( w = 0; w < nvars; ++w ) 8266 { 8267 assert(clqpart[w] >= 0 && clqpart[w] <= w); 8268 if( clqpart[w] == cliquenum ) 8269 { 8270 if( maxactduetoclqfront + weights[w] <= capacity ) 8271 { 8272 maxactduetoclqfront += weights[w]; 8273 ++cliquenum; 8274 } 8275 else 8276 break; 8277 } 8278 sumfront += weights[w]; 8279 } 8280 assert(w >= v); 8281 8282 /* if all items fit, then delete the whole constraint but create clique constraints which led to this 8283 * information 8284 */ 8285 if( conshdlrdata->disaggregation && w == nvars ) 8286 { 8287 SCIP_VAR** clqvars; 8288 int nclqvars; 8289 int c; 8290 int ncliques; 8291 8292 assert(maxactduetoclqfront <= capacity); 8293 8294 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons)); 8295 8296 ncliques = consdata->ncliques; 8297 8298 /* allocate temporary memory */ 8299 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) ); 8300 8301 for( c = 0; c < ncliques; ++c ) 8302 { 8303 nclqvars = 0; 8304 for( w = 0; w < nvars; ++w ) 8305 { 8306 if( clqpart[w] == c ) 8307 { 8308 clqvars[nclqvars] = vars[w]; 8309 ++nclqvars; 8310 } 8311 } 8312 8313 /* we found a real clique so extract this constraint, because we do not know who this information generated so */ 8314 if( nclqvars > 1 ) 8315 { 8316 SCIP_CONS* cliquecons; 8317 char name[SCIP_MAXSTRLEN]; 8318 8319 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c); 8320 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars, 8321 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 8322 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 8323 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), 8324 SCIPconsIsStickingAtNode(cons)) ); 8325 SCIPdebugMsg(scip, " -> adding clique constraint: "); 8326 SCIPdebugPrintCons(scip, cliquecons, NULL); 8327 SCIP_CALL( SCIPaddCons(scip, cliquecons) ); 8328 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) ); 8329 ++(*naddconss); 8330 } 8331 } 8332 8333 /* delete old constraint */ 8334 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 8335 ++(*ndelconss); 8336 8337 SCIPfreeBufferArray(scip, &clqvars); 8338 8339 return SCIP_OKAY; 8340 } 8341 8342 if( w > v && w < nvars - 1 ) 8343 { 8344 /* try to delete variables */ 8345 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) ); 8346 } 8347 } 8348 8349 return SCIP_OKAY; 8350 } 8351 8352 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */ 8353 static 8354 void normalizeWeights( 8355 SCIP_CONS* cons, /**< knapsack constraint */ 8356 int* nchgcoefs, /**< pointer to count total number of changed coefficients */ 8357 int* nchgsides /**< pointer to count number of side changes */ 8358 ) 8359 { 8360 SCIP_CONSDATA* consdata; 8361 SCIP_Longint gcd; 8362 int i; 8363 8364 assert(nchgcoefs != NULL); 8365 assert(nchgsides != NULL); 8366 assert(!SCIPconsIsModifiable(cons)); 8367 8368 consdata = SCIPconsGetData(cons); 8369 assert(consdata != NULL); 8370 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */ 8371 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */ 8372 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */ 8373 assert(consdata->nvars >= 1); 8374 8375 /* sort items, because we can stop earlier if the smaller weights are evaluated first */ 8376 sortItems(consdata); 8377 8378 gcd = consdata->weights[consdata->nvars-1]; 8379 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i ) 8380 { 8381 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5); 8382 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */ 8383 8384 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]); 8385 } 8386 8387 if( gcd >= 2 ) 8388 { 8389 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd); 8390 8391 for( i = 0; i < consdata->nvars; ++i ) 8392 { 8393 consdataChgWeight(consdata, i, consdata->weights[i]/gcd); 8394 } 8395 consdata->capacity /= gcd; 8396 (*nchgcoefs) += consdata->nvars; 8397 (*nchgsides)++; 8398 8399 /* weight should still be sorted, because the reduction preserves this */ 8400 #ifndef NDEBUG 8401 for( i = consdata->nvars - 1; i > 0; --i ) 8402 assert(consdata->weights[i] <= consdata->weights[i - 1]); 8403 #endif 8404 consdata->sorted = TRUE; 8405 } 8406 } 8407 8408 /** dual weights tightening for knapsack constraints 8409 * 8410 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint 8411 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor 8412 * constraint 8413 * 8414 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of 8415 * these are a minimal cover, then might reduce the weights and the capacity, e.g. 8416 * 8417 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3 8418 * 8419 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g. 8420 * 8421 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13 8422 * 8423 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13 8424 * 8425 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42 8426 */ 8427 static 8428 SCIP_RETCODE dualWeightsTightening( 8429 SCIP* scip, /**< SCIP data structure */ 8430 SCIP_CONS* cons, /**< knapsack constraint */ 8431 int* ndelconss, /**< pointer to store the amount of deleted constraints */ 8432 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */ 8433 int* nchgsides, /**< pointer to store the amount of changed sides */ 8434 int* naddconss /**< pointer to count number of added constraints */ 8435 ) 8436 { 8437 SCIP_CONSDATA* consdata; 8438 SCIP_Longint* weights; 8439 SCIP_Longint dualcapacity; 8440 SCIP_Longint reductionsum; 8441 SCIP_Longint capacity; 8442 SCIP_Longint exceedsum; 8443 int oldnchgcoefs; 8444 int nvars; 8445 int vbig; 8446 int v; 8447 int w; 8448 #ifndef NDEBUG 8449 int oldnchgsides; 8450 #endif 8451 8452 assert(scip != NULL); 8453 assert(cons != NULL); 8454 assert(ndelconss != NULL); 8455 assert(nchgcoefs != NULL); 8456 assert(nchgsides != NULL); 8457 assert(naddconss != NULL); 8458 8459 #ifndef NDEBUG 8460 oldnchgsides = *nchgsides; 8461 #endif 8462 8463 consdata = SCIPconsGetData(cons); 8464 assert(consdata != NULL); 8465 assert(consdata->weightsum > consdata->capacity); 8466 assert(consdata->nvars >= 2); 8467 assert(consdata->sorted); 8468 8469 /* constraint should be merged */ 8470 assert(consdata->merged); 8471 8472 nvars = consdata->nvars; 8473 weights = consdata->weights; 8474 capacity = consdata->capacity; 8475 8476 oldnchgcoefs = *nchgcoefs; 8477 8478 /* case 1. */ 8479 if( weights[nvars - 1] + weights[nvars - 2] > capacity ) 8480 { 8481 SCIP_CONS* newcons; 8482 8483 /* two variable are enough to exceed the constraint, so we can update it to a set-packing 8484 * 8485 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1 8486 */ 8487 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons)); 8488 8489 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars, 8490 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 8491 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 8492 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), 8493 SCIPconsIsStickingAtNode(cons)) ); 8494 8495 SCIP_CALL( SCIPaddCons(scip, newcons) ); 8496 SCIP_CALL( SCIPreleaseCons(scip, &newcons) ); 8497 ++(*naddconss); 8498 8499 SCIP_CALL( SCIPdelCons(scip, cons) ); 8500 ++(*ndelconss); 8501 8502 return SCIP_OKAY; 8503 } 8504 8505 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */ 8506 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity ) 8507 { 8508 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) ); 8509 assert(SCIPconsIsDeleted(cons)); 8510 8511 return SCIP_OKAY; 8512 } 8513 8514 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */ 8515 /* @todo might be changed/removed when improving the coeffcients tightening */ 8516 if( consdata->weightsum - capacity > weights[0] + weights[1] ) 8517 return SCIP_OKAY; 8518 8519 /* case 2. */ 8520 8521 v = 0; 8522 8523 /* @todo generalize the following algorithm for several parts of the knapsack 8524 * 8525 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of 8526 * variables each combination is a minimal cover, some examples 8527 * 8528 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103 8529 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2 8530 * <=> x1 + x2 + x3 + x4 + x5 <= 3 8531 * 8532 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3 8533 * 8534 */ 8535 8536 /* determine big weights that fit only by itself */ 8537 while( v < nvars && weights[v] + weights[nvars - 1] > capacity ) 8538 ++v; 8539 8540 vbig = v; 8541 assert(vbig < nvars - 1); 8542 exceedsum = 0; 8543 8544 /* determine the amount needed to exceed the capacity */ 8545 while( v < nvars && exceedsum <= capacity ) 8546 { 8547 exceedsum += weights[v]; 8548 ++v; 8549 } 8550 8551 /* if we exceeded the capacity we might reduce the weights */ 8552 if( exceedsum > capacity ) 8553 { 8554 assert(vbig > 0 || v < nvars); 8555 8556 /* all small weights were needed to exceed the capacity */ 8557 if( v == nvars ) 8558 { 8559 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1; 8560 assert(newweight > 0); 8561 8562 /* reduce big weights */ 8563 for( v = 0; v < vbig; ++v ) 8564 { 8565 if( weights[v] > newweight ) 8566 { 8567 consdataChgWeight(consdata, v, newweight); 8568 ++(*nchgcoefs); 8569 } 8570 } 8571 8572 /* reduce small weights */ 8573 for( ; v < nvars; ++v ) 8574 { 8575 if( weights[v] > 1 ) 8576 { 8577 consdataChgWeight(consdata, v, 1LL); 8578 ++(*nchgcoefs); 8579 } 8580 } 8581 8582 consdata->capacity = newweight; 8583 8584 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal 8585 * weight must not be sorted by their index 8586 */ 8587 #ifndef NDEBUG 8588 for( v = nvars - 1; v > 0; --v ) 8589 assert(weights[v] <= weights[v-1]); 8590 #endif 8591 8592 return SCIP_OKAY; 8593 } 8594 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the 8595 * small weights 8596 */ 8597 else 8598 { 8599 SCIP_Longint exceedsumback = 0; 8600 int nexceed = v - vbig; 8601 8602 assert(nexceed > 1); 8603 8604 /* determine weightsum of the same amount as before but of the smallest weight */ 8605 for( w = nvars - 1; w >= nvars - nexceed; --w ) 8606 exceedsumback += weights[w]; 8607 8608 assert(w >= 0); 8609 8610 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all 8611 * combinations of all small weights 8612 */ 8613 if( exceedsumback > capacity ) 8614 { 8615 SCIP_Longint newweight = nexceed - 1; 8616 8617 /* taking out the smallest element needs to fit */ 8618 assert(exceedsumback - weights[nvars - 1] <= capacity); 8619 8620 /* reduce big weights */ 8621 for( v = 0; v < vbig; ++v ) 8622 { 8623 if( weights[v] > newweight ) 8624 { 8625 consdataChgWeight(consdata, v, newweight); 8626 ++(*nchgcoefs); 8627 } 8628 } 8629 8630 /* reduce small weights */ 8631 for( ; v < nvars; ++v ) 8632 { 8633 if( weights[v] > 1 ) 8634 { 8635 consdataChgWeight(consdata, v, 1LL); 8636 ++(*nchgcoefs); 8637 } 8638 } 8639 8640 consdata->capacity = newweight; 8641 8642 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal 8643 * weight must not be sorted by their index 8644 */ 8645 #ifndef NDEBUG 8646 for( v = nvars - 1; v > 0; --v ) 8647 assert(weights[v] <= weights[v-1]); 8648 #endif 8649 return SCIP_OKAY; 8650 } 8651 } 8652 } 8653 else 8654 { 8655 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should 8656 * not happen here 8657 */ 8658 assert(vbig > 0 && vbig < nvars); 8659 8660 /* either choose a big coefficients or all other variables 8661 * 8662 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979 8663 * 8664 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this 8665 * constraint to 8666 * 8667 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9 8668 */ 8669 8670 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 ) 8671 { 8672 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig; 8673 #ifndef NDEBUG 8674 SCIP_Longint resweightsum = consdata->weightsum; 8675 8676 for( v = 0; v < vbig; ++v ) 8677 resweightsum -= weights[v]; 8678 8679 assert(exceedsum == resweightsum); 8680 #endif 8681 assert(newweight > 0); 8682 8683 /* reduce big weights */ 8684 for( v = 0; v < vbig; ++v ) 8685 { 8686 if( weights[v] > newweight ) 8687 { 8688 consdataChgWeight(consdata, v, newweight); 8689 ++(*nchgcoefs); 8690 } 8691 } 8692 8693 /* reduce small weights */ 8694 for( ; v < nvars; ++v ) 8695 { 8696 if( weights[v] > 1 ) 8697 { 8698 consdataChgWeight(consdata, v, 1LL); 8699 ++(*nchgcoefs); 8700 } 8701 } 8702 8703 consdata->capacity = newweight; 8704 8705 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal 8706 * weight must not be sorted by their index 8707 */ 8708 #ifndef NDEBUG 8709 for( v = nvars - 1; v > 0; --v ) 8710 assert(weights[v] <= weights[v-1]); 8711 #endif 8712 return SCIP_OKAY; 8713 } 8714 } 8715 8716 /* case 3. */ 8717 8718 dualcapacity = consdata->weightsum - capacity; 8719 reductionsum = 0; 8720 v = 0; 8721 8722 /* reduce big weights 8723 * 8724 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10 8725 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10 8726 * <=> x0 + x1 + x2 + x3 <= 3 8727 */ 8728 while( weights[v] > dualcapacity ) 8729 { 8730 reductionsum += (weights[v] - dualcapacity); 8731 consdataChgWeight(consdata, v, dualcapacity); 8732 ++v; 8733 assert(v < nvars); 8734 } 8735 (*nchgcoefs) += v; 8736 8737 /* skip weights equal to the dualcapacity, because we cannot change them */ 8738 while( v < nvars && weights[v] == dualcapacity ) 8739 ++v; 8740 8741 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor 8742 * after a possible removal of the last, redundant item 8743 * 8744 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1 8745 */ 8746 if( v >= nvars - 1 ) 8747 { 8748 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */ 8749 if( v == nvars - 1 ) 8750 { 8751 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) ); 8752 } 8753 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) ); 8754 assert(SCIPconsIsDeleted(cons)); 8755 8756 return SCIP_OKAY; 8757 } 8758 else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */ 8759 { 8760 /* @todo generalize the following algorithm for more than two variables */ 8761 8762 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity ) 8763 { 8764 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big 8765 * coefficients) of all or two variables of the rest 8766 * 8767 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9 8768 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2 8769 * <=> 2x1 + 2x2 + x3 + x4 <= 4 8770 * 8771 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3 8772 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2 8773 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7 8774 * 8775 */ 8776 if( v > 0 && weights[nvars - 2] > 1 ) 8777 { 8778 int ncoefchg = 0; 8779 8780 /* reduce all bigger weights */ 8781 for( w = 0; w < v; ++w ) 8782 { 8783 if( weights[w] > 2 ) 8784 { 8785 consdataChgWeight(consdata, w, 2LL); 8786 ++ncoefchg; 8787 } 8788 else 8789 { 8790 assert(weights[0] == 2); 8791 assert(weights[v - 1] == 2); 8792 break; 8793 } 8794 } 8795 8796 /* reduce all smaller weights */ 8797 for( w = v; w < nvars; ++w ) 8798 { 8799 if( weights[w] > 1 ) 8800 { 8801 consdataChgWeight(consdata, w, 1LL); 8802 ++ncoefchg; 8803 } 8804 } 8805 assert(ncoefchg > 0); 8806 8807 (*nchgcoefs) += ncoefchg; 8808 8809 /* correct the capacity */ 8810 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/ 8811 assert(consdata->capacity > 0); 8812 assert(weights[0] <= consdata->capacity); 8813 assert(consdata->weightsum > consdata->capacity); 8814 /* reset the reductionsum */ 8815 reductionsum = 0; 8816 } 8817 else if( v == 0 ) 8818 { 8819 assert(weights[nvars - 2] == 1); 8820 } 8821 } 8822 else 8823 { 8824 SCIP_Longint minweight = weights[nvars - 1]; 8825 SCIP_Longint newweight = dualcapacity - minweight; 8826 SCIP_Longint restsumweights = 0; 8827 SCIP_Longint sumcoef; 8828 SCIP_Bool sumcoefcase = FALSE; 8829 int startv = v; 8830 int end; 8831 int k; 8832 8833 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity); 8834 8835 /* reduce big weights of pairs that exceed the dualcapacity 8836 * 8837 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9 8838 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9 8839 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27 8840 */ 8841 while( weights[v] > newweight ) 8842 { 8843 reductionsum += (weights[v] - newweight); 8844 consdataChgWeight(consdata, v, newweight); 8845 ++v; 8846 assert(v < nvars); 8847 } 8848 (*nchgcoefs) += (v - startv); 8849 8850 /* skip equal weights */ 8851 while( weights[v] == newweight ) 8852 ++v; 8853 8854 if( v > 0 ) 8855 { 8856 for( w = v; w < nvars; ++w ) 8857 restsumweights += weights[w]; 8858 } 8859 else 8860 restsumweights = consdata->weightsum; 8861 8862 if( restsumweights < dualcapacity ) 8863 { 8864 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g. 8865 * 8866 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=> 8867 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61 8868 */ 8869 if( startv == v ) 8870 { 8871 /* remove redundant variables */ 8872 for( w = nvars - 1; w >= v; --w ) 8873 { 8874 SCIP_CALL( delCoefPos(scip, cons, v) ); 8875 ++(*nchgcoefs); 8876 } 8877 8878 #ifndef NDEBUG 8879 /* each coefficients should exceed the dualcapacity by itself */ 8880 for( ; w >= 0; --w ) 8881 assert(weights[w] == dualcapacity); 8882 #endif 8883 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly 8884 * upgrade this constraint 8885 */ 8886 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) ); 8887 assert(SCIPconsIsDeleted(cons)); 8888 8889 return SCIP_OKAY; 8890 } 8891 8892 /* special case where we have three different coefficient types 8893 * 8894 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9 8895 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9 8896 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3 8897 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9 8898 */ 8899 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) ) 8900 { 8901 SCIP_Longint newcap; 8902 8903 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */ 8904 for( w = nvars - 1; w >= v; --w ) 8905 { 8906 if( weights[w] > 1 ) 8907 { 8908 consdataChgWeight(consdata, w, 1LL); 8909 ++(*nchgcoefs); 8910 } 8911 } 8912 8913 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the 8914 * dualcapacity 8915 */ 8916 newweight = (SCIP_Longint)nvars - v; 8917 assert(newweight > 1); 8918 for( ; w >= startv; --w ) 8919 { 8920 if( weights[w] > newweight ) 8921 { 8922 consdataChgWeight(consdata, w, newweight); 8923 ++(*nchgcoefs); 8924 } 8925 else 8926 assert(weights[w] == newweight); 8927 } 8928 8929 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */ 8930 ++newweight; 8931 assert(newweight > 2); 8932 for( ; w >= 0; --w ) 8933 { 8934 if( weights[w] > newweight ) 8935 { 8936 consdataChgWeight(consdata, w, newweight); 8937 ++(*nchgcoefs); 8938 } 8939 else 8940 assert(weights[w] == newweight); 8941 } 8942 8943 /* update the capacity */ 8944 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v); 8945 if( consdata->capacity > newcap ) 8946 { 8947 consdata->capacity = newcap; 8948 ++(*nchgsides); 8949 } 8950 else 8951 assert(consdata->capacity == newcap); 8952 } 8953 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1)); 8954 8955 /* the new dualcapacity should still be equal to the (nvars - v + 1) */ 8956 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1); 8957 8958 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal 8959 * weight must not be sorted by their index 8960 */ 8961 #ifndef NDEBUG 8962 for( w = nvars - 1; w > 0; --w ) 8963 assert(weights[w] <= weights[w - 1]); 8964 #endif 8965 return SCIP_OKAY; 8966 } 8967 8968 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */ 8969 end = nvars - 2; 8970 while( end >= 0 && weights[end] == weights[end + 1] ) 8971 { 8972 assert(end >= v); 8973 --end; 8974 } 8975 8976 if( v >= end ) 8977 goto TERMINATE; 8978 8979 end = nvars - 2; 8980 8981 /* can we stop early, another special reduction case might exist */ 8982 if( 2 * weights[end] > dualcapacity ) 8983 { 8984 restsumweights = 0; 8985 8986 /* determine capacity of the small items */ 8987 for( w = end + 1; w < nvars; ++w ) 8988 restsumweights += weights[w]; 8989 8990 if( restsumweights * 2 <= dualcapacity ) 8991 { 8992 /* check for further posssible reductions in the middle */ 8993 while( v < end && restsumweights + weights[v] >= dualcapacity ) 8994 ++v; 8995 8996 if( v >= end ) 8997 goto TERMINATE; 8998 8999 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */ 9000 if( (dualcapacity & 1) == 0 ) 9001 { 9002 newweight = dualcapacity / 2; 9003 9004 /* set all middle coefficients */ 9005 for( ; v <= end; ++v ) 9006 { 9007 if( weights[v] > newweight ) 9008 { 9009 reductionsum += (weights[v] - newweight); 9010 consdataChgWeight(consdata, v, newweight); 9011 ++(*nchgcoefs); 9012 } 9013 } 9014 } 9015 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all 9016 * other coefficients by 2 9017 */ 9018 else 9019 { 9020 /* correct the reductionsum */ 9021 reductionsum *= 2; 9022 9023 /* multiply big coefficients by 2 */ 9024 for( w = 0; w < v; ++w ) 9025 { 9026 consdataChgWeight(consdata, w, weights[w] * 2); 9027 } 9028 9029 newweight = dualcapacity; 9030 /* set all middle coefficients */ 9031 for( ; v <= end; ++v ) 9032 { 9033 reductionsum += (2 * weights[v] - newweight); 9034 consdataChgWeight(consdata, v, newweight); 9035 } 9036 9037 /* multiply small coefficients by 2 */ 9038 for( w = end + 1; w < nvars; ++w ) 9039 { 9040 consdataChgWeight(consdata, w, weights[w] * 2); 9041 } 9042 (*nchgcoefs) += nvars; 9043 9044 dualcapacity *= 2; 9045 consdata->capacity *= 2; 9046 ++(*nchgsides); 9047 } 9048 } 9049 9050 goto TERMINATE; 9051 } 9052 9053 /* further reductions using the next possible coefficient sum 9054 * 9055 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9 9056 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9 9057 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18 9058 */ 9059 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */ 9060 for( k = 0; k < 4; ++k ) 9061 { 9062 /* determine next minimal coefficient sum */ 9063 switch( k ) 9064 { 9065 case 0: 9066 sumcoef = weights[nvars - 1] + weights[nvars - 2]; 9067 break; 9068 case 1: 9069 assert(nvars >= 3); 9070 sumcoef = weights[nvars - 1] + weights[nvars - 3]; 9071 break; 9072 case 2: 9073 assert(nvars >= 4); 9074 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] ) 9075 { 9076 sumcoefcase = TRUE; 9077 sumcoef = weights[nvars - 1] + weights[nvars - 4]; 9078 } 9079 else 9080 { 9081 sumcoefcase = FALSE; 9082 sumcoef = weights[nvars - 2] + weights[nvars - 3]; 9083 } 9084 break; 9085 case 3: 9086 assert(nvars >= 5); 9087 if( sumcoefcase ) 9088 { 9089 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]); 9090 } 9091 else 9092 { 9093 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]); 9094 } 9095 break; 9096 default: 9097 return SCIP_ERROR; 9098 } 9099 9100 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */ 9101 minweight = weights[end]; 9102 while( minweight <= sumcoef ) 9103 { 9104 newweight = dualcapacity - minweight; 9105 startv = v; 9106 assert(v < nvars); 9107 9108 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */ 9109 /* shrink big coefficients */ 9110 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity ) 9111 { 9112 reductionsum += (weights[v] - newweight); 9113 consdataChgWeight(consdata, v, newweight); 9114 ++v; 9115 assert(v < nvars); 9116 } 9117 (*nchgcoefs) += (v - startv); 9118 9119 /* skip unchangable weights */ 9120 while( weights[v] + minweight == dualcapacity ) 9121 { 9122 assert(v < nvars); 9123 ++v; 9124 } 9125 9126 --end; 9127 /* skip same end weights */ 9128 while( end >= 0 && weights[end] == weights[end + 1] ) 9129 --end; 9130 9131 if( v >= end ) 9132 goto TERMINATE; 9133 9134 minweight = weights[end]; 9135 } 9136 9137 if( v >= end ) 9138 goto TERMINATE; 9139 9140 /* now check if a combination of small coefficients allows us to tighten big coefficients further */ 9141 if( sumcoef < minweight ) 9142 { 9143 minweight = sumcoef; 9144 newweight = dualcapacity - minweight; 9145 startv = v; 9146 assert(v < nvars); 9147 9148 /* shrink big coefficients */ 9149 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity ) 9150 { 9151 reductionsum += (weights[v] - newweight); 9152 consdataChgWeight(consdata, v, newweight); 9153 ++v; 9154 assert(v < nvars); 9155 } 9156 (*nchgcoefs) += (v - startv); 9157 9158 /* skip unchangable weights */ 9159 while( weights[v] + minweight == dualcapacity ) 9160 { 9161 assert(v < nvars); 9162 ++v; 9163 } 9164 } 9165 9166 if( v >= end ) 9167 goto TERMINATE; 9168 9169 /* can we stop early, another special reduction case might exist */ 9170 if( 2 * weights[end] > dualcapacity ) 9171 { 9172 restsumweights = 0; 9173 9174 /* determine capacity of the small items */ 9175 for( w = end + 1; w < nvars; ++w ) 9176 restsumweights += weights[w]; 9177 9178 if( restsumweights * 2 <= dualcapacity ) 9179 { 9180 /* check for further posssible reductions in the middle */ 9181 while( v < end && restsumweights + weights[v] >= dualcapacity ) 9182 ++v; 9183 9184 if( v >= end ) 9185 goto TERMINATE; 9186 9187 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */ 9188 if( (dualcapacity & 1) == 0 ) 9189 { 9190 newweight = dualcapacity / 2; 9191 9192 /* set all middle coefficients */ 9193 for( ; v <= end; ++v ) 9194 { 9195 if( weights[v] > newweight ) 9196 { 9197 reductionsum += (weights[v] - newweight); 9198 consdataChgWeight(consdata, v, newweight); 9199 ++(*nchgcoefs); 9200 } 9201 } 9202 } 9203 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all 9204 * other coefficients by 2 9205 */ 9206 else 9207 { 9208 /* correct the reductionsum */ 9209 reductionsum *= 2; 9210 9211 /* multiply big coefficients by 2 */ 9212 for( w = 0; w < v; ++w ) 9213 { 9214 consdataChgWeight(consdata, w, weights[w] * 2); 9215 } 9216 9217 newweight = dualcapacity; 9218 /* set all middle coefficients */ 9219 for( ; v <= end; ++v ) 9220 { 9221 reductionsum += (2 * weights[v] - newweight); 9222 consdataChgWeight(consdata, v, newweight); 9223 } 9224 9225 /* multiply small coefficients by 2 */ 9226 for( w = end + 1; w < nvars; ++w ) 9227 { 9228 consdataChgWeight(consdata, w, weights[w] * 2); 9229 } 9230 (*nchgcoefs) += nvars; 9231 9232 dualcapacity *= 2; 9233 consdata->capacity *= 2; 9234 ++(*nchgsides); 9235 } 9236 } 9237 9238 goto TERMINATE; 9239 } 9240 9241 /* cannot tighten any further */ 9242 if( 2 * sumcoef > dualcapacity ) 9243 goto TERMINATE; 9244 } 9245 } 9246 } 9247 9248 TERMINATE: 9249 /* correct capacity */ 9250 if( reductionsum > 0 ) 9251 { 9252 assert(v > 0); 9253 9254 consdata->capacity -= reductionsum; 9255 ++(*nchgsides); 9256 9257 assert(consdata->weightsum - dualcapacity == consdata->capacity); 9258 } 9259 assert(weights[0] <= consdata->capacity); 9260 9261 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal 9262 * weight must not be sorted by their index 9263 */ 9264 #ifndef NDEBUG 9265 for( w = nvars - 1; w > 0; --w ) 9266 assert(weights[w] <= weights[w - 1]); 9267 #endif 9268 9269 if( oldnchgcoefs < *nchgcoefs ) 9270 { 9271 assert(!SCIPconsIsDeleted(cons)); 9272 9273 /* it might be that we can divide the weights by their greatest common divisor */ 9274 normalizeWeights(cons, nchgcoefs, nchgsides); 9275 } 9276 else 9277 { 9278 assert(oldnchgcoefs == *nchgcoefs); 9279 assert(oldnchgsides == *nchgsides); 9280 } 9281 9282 return SCIP_OKAY; 9283 } 9284 9285 9286 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */ 9287 static 9288 SCIP_RETCODE prepareCons( 9289 SCIP* scip, /**< SCIP data structure */ 9290 SCIP_CONS* cons, /**< knapsack constraint */ 9291 int* nfixedvars, /**< pointer to store the amount of fixed variables */ 9292 int* ndelconss, /**< pointer to store the amount of deleted constraints */ 9293 int* nchgcoefs /**< pointer to store the amount of changed coefficients */ 9294 ) 9295 { 9296 SCIP_VAR** vars; 9297 SCIP_CONSDATA* consdata; 9298 SCIP_Longint* weights; 9299 SCIP_Longint capacity; 9300 SCIP_Bool infeasible; 9301 SCIP_Bool fixed; 9302 int nvars; 9303 int v; 9304 9305 assert(scip != NULL); 9306 assert(cons != NULL); 9307 assert(nfixedvars != NULL); 9308 assert(ndelconss != NULL); 9309 assert(nchgcoefs != NULL); 9310 9311 consdata = SCIPconsGetData(cons); 9312 assert(consdata != NULL); 9313 9314 nvars = consdata->nvars; 9315 9316 /* no variables left, then delete constraint */ 9317 if( nvars == 0 ) 9318 { 9319 assert(consdata->capacity >= 0); 9320 9321 SCIP_CALL( SCIPdelCons(scip, cons) ); 9322 ++(*ndelconss); 9323 9324 return SCIP_OKAY; 9325 } 9326 9327 /* sort items */ 9328 sortItems(consdata); 9329 9330 vars = consdata->vars; 9331 weights = consdata->weights; 9332 capacity = consdata->capacity; 9333 v = 0; 9334 9335 /* check for weights bigger than the capacity */ 9336 while( v < nvars && weights[v] > capacity ) 9337 { 9338 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) ); 9339 assert(!infeasible); 9340 9341 if( fixed ) 9342 ++(*nfixedvars); 9343 9344 ++v; 9345 } 9346 9347 /* if we fixed at least one variable we need to delete them from the constraint */ 9348 if( v > 0 ) 9349 { 9350 if( v == nvars ) 9351 { 9352 SCIP_CALL( SCIPdelCons(scip, cons) ); 9353 ++(*ndelconss); 9354 9355 return SCIP_OKAY; 9356 } 9357 9358 /* delete all position from back to front */ 9359 for( --v; v >= 0; --v ) 9360 { 9361 SCIP_CALL( delCoefPos(scip, cons, v) ); 9362 ++(*nchgcoefs); 9363 } 9364 9365 /* sort items again because of deletion */ 9366 sortItems(consdata); 9367 assert(vars == consdata->vars); 9368 assert(weights == consdata->weights); 9369 } 9370 assert(consdata->sorted); 9371 assert(weights[0] <= capacity); 9372 9373 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity ) 9374 { 9375 SCIP_CALL( SCIPdelCons(scip, cons) ); 9376 ++(*ndelconss); 9377 } 9378 9379 return SCIP_OKAY; 9380 } 9381 9382 9383 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity 9384 * 9385 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g. 9386 * 9387 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13 9388 * 9389 * the above constraint can be changed to 9390 * 9391 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20 9392 * 9393 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g. 9394 * 9395 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed 9396 * 9397 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the 9398 * constraint further, e.g. 9399 * 9400 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4 9401 * => 2x1 + x2 + x3 + x4 <= 2 9402 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above 9403 */ 9404 static 9405 SCIP_RETCODE simplifyInequalities( 9406 SCIP* scip, /**< SCIP data structure */ 9407 SCIP_CONS* cons, /**< knapsack constraint */ 9408 int* nfixedvars, /**< pointer to store the amount of fixed variables */ 9409 int* ndelconss, /**< pointer to store the amount of deleted constraints */ 9410 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */ 9411 int* nchgsides, /**< pointer to store the amount of changed sides */ 9412 int* naddconss, /**< pointer to count number of added constraints */ 9413 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */ 9414 ) 9415 { 9416 SCIP_VAR** vars; 9417 SCIP_CONSDATA* consdata; 9418 SCIP_Longint* weights; 9419 SCIP_Longint restweight; 9420 SCIP_Longint newweight; 9421 SCIP_Longint weight; 9422 SCIP_Longint oldgcd; 9423 SCIP_Longint rest; 9424 SCIP_Longint gcd; 9425 int oldnchgcoefs; 9426 int oldnchgsides; 9427 int candpos; 9428 int candpos2; 9429 int offsetv; 9430 int nvars; 9431 int v; 9432 9433 assert(scip != NULL); 9434 assert(cons != NULL); 9435 assert(nfixedvars != NULL); 9436 assert(ndelconss != NULL); 9437 assert(nchgcoefs != NULL); 9438 assert(nchgsides != NULL); 9439 assert(naddconss != NULL); 9440 assert(cutoff != NULL); 9441 assert(!SCIPconsIsModifiable(cons)); 9442 9443 consdata = SCIPconsGetData(cons); 9444 assert( consdata != NULL ); 9445 9446 *cutoff = FALSE; 9447 9448 /* remove double enties and also combinations of active and negated variables */ 9449 SCIP_CALL( mergeMultiples(scip, cons, cutoff) ); 9450 assert(consdata->merged); 9451 if( *cutoff ) 9452 return SCIP_OKAY; 9453 9454 assert(consdata->capacity >= 0); 9455 9456 /* fix variables with big coefficients and remove redundant constraints, sort weights */ 9457 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) ); 9458 9459 if( SCIPconsIsDeleted(cons) ) 9460 return SCIP_OKAY; 9461 9462 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) ) 9463 { 9464 /* 1. dual weights tightening */ 9465 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) ); 9466 9467 if( SCIPconsIsDeleted(cons) ) 9468 return SCIP_OKAY; 9469 /* 2. delete redundant variables */ 9470 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) ); 9471 9472 if( SCIPconsIsDeleted(cons) ) 9473 return SCIP_OKAY; 9474 } 9475 9476 weights = consdata->weights; 9477 nvars = consdata->nvars; 9478 9479 #ifndef NDEBUG 9480 /* constraint might not be sorted, but the weights are already sorted */ 9481 for( v = nvars - 1; v > 0; --v ) 9482 assert(weights[v] <= weights[v-1]); 9483 #endif 9484 9485 /* determine greatest common divisor */ 9486 gcd = weights[nvars - 1]; 9487 for( v = nvars - 2; v >= 0 && gcd > 1; --v ) 9488 { 9489 gcd = SCIPcalcGreComDiv(gcd, weights[v]); 9490 } 9491 9492 /* divide the constraint by their greatest common divisor */ 9493 if( gcd >= 2 ) 9494 { 9495 for( v = nvars - 1; v >= 0; --v ) 9496 { 9497 consdataChgWeight(consdata, v, weights[v]/gcd); 9498 } 9499 (*nchgcoefs) += nvars; 9500 9501 consdata->capacity /= gcd; 9502 (*nchgsides)++; 9503 } 9504 assert(consdata->nvars == nvars); 9505 9506 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight 9507 * must not be sorted by their index 9508 */ 9509 #ifndef NDEBUG 9510 for( v = nvars - 1; v > 0; --v ) 9511 assert(weights[v] <= weights[v-1]); 9512 #endif 9513 9514 /* 3. start gcd procedure for all variables */ 9515 do 9516 { 9517 SCIPdebug( oldnchgcoefs = *nchgcoefs; ) 9518 SCIPdebug( oldnchgsides = *nchgsides; ) 9519 9520 vars = consdata->vars; 9521 weights = consdata->weights; 9522 nvars = consdata->nvars; 9523 9524 /* stop if we have two coefficients which are one in absolute value */ 9525 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 ) 9526 return SCIP_OKAY; 9527 9528 v = 0; 9529 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the 9530 * gcd 9531 */ 9532 while( weights[v] == consdata->capacity ) 9533 { 9534 ++v; 9535 assert(v < nvars); 9536 } 9537 9538 /* all but one variable are as big as the capacity, this is handled elsewhere */ 9539 if( v == nvars - 1 ) 9540 return SCIP_OKAY; 9541 9542 offsetv = v; 9543 9544 gcd = -1; 9545 candpos = -1; 9546 candpos2 = -1; 9547 9548 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might 9549 * change the coefficient 9550 */ 9551 for( v = nvars - 1; v >= offsetv; --v ) 9552 { 9553 weight = weights[v]; 9554 assert(weight >= 1); 9555 9556 oldgcd = gcd; 9557 9558 if( gcd == -1 ) 9559 { 9560 gcd = weights[v]; 9561 assert(gcd >= 1); 9562 } 9563 else 9564 { 9565 /* calculate greatest common divisor for all variables */ 9566 gcd = SCIPcalcGreComDiv(gcd, weight); 9567 } 9568 9569 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we 9570 * can terminate 9571 */ 9572 if( gcd == 1 ) 9573 { 9574 /* found candidate */ 9575 if( candpos == -1 ) 9576 { 9577 gcd = oldgcd; 9578 candpos = v; 9579 9580 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */ 9581 if( v == nvars - 2 ) 9582 candpos2 = v + 1; 9583 } 9584 /* two different variables lead to a gcd of one, so we cannot change a coefficient */ 9585 else 9586 { 9587 if( candpos == v + 1 && candpos2 == v + 2 ) 9588 { 9589 assert(candpos2 == nvars - 1); 9590 9591 /* take new candidates */ 9592 candpos = candpos2; 9593 9594 /* recalculate gcd from scratch */ 9595 gcd = weights[v+1]; 9596 assert(gcd >= 1); 9597 9598 /* calculate greatest common divisor for variables */ 9599 gcd = SCIPcalcGreComDiv(gcd, weights[v]); 9600 if( gcd == 1 ) 9601 return SCIP_OKAY; 9602 } 9603 else 9604 /* cannot determine a possible coefficient for reduction */ 9605 return SCIP_OKAY; 9606 } 9607 } 9608 } 9609 assert(gcd >= 2); 9610 9611 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint 9612 * further 9613 */ 9614 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars); 9615 9616 /* determine the remainder of the capacity and the gcd */ 9617 rest = consdata->capacity % gcd; 9618 assert(rest >= 0); 9619 assert(rest < gcd); 9620 9621 if( candpos == -1 ) 9622 { 9623 /* we assume that the constraint was normalized */ 9624 assert(rest > 0); 9625 9626 /* replace old with new capacity */ 9627 consdata->capacity -= rest; 9628 ++(*nchgsides); 9629 9630 /* replace old big coefficients with new capacity */ 9631 for( v = 0; v < offsetv; ++v ) 9632 { 9633 consdataChgWeight(consdata, v, consdata->capacity); 9634 } 9635 9636 *nchgcoefs += offsetv; 9637 goto CONTINUE; 9638 } 9639 9640 /* determine the remainder of the coefficient candidate and the gcd */ 9641 restweight = weights[candpos] % gcd; 9642 assert(restweight >= 1); 9643 assert(restweight < gcd); 9644 9645 /* calculate new coefficient */ 9646 if( restweight > rest ) 9647 newweight = weights[candpos] - restweight + gcd; 9648 else 9649 newweight = weights[candpos] - restweight; 9650 9651 assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd); 9652 9653 SCIPdebugMsg(scip, "gcd = %" SCIP_LONGINT_FORMAT ", rest = %" SCIP_LONGINT_FORMAT ", restweight = %" SCIP_LONGINT_FORMAT "; possible new weight of variable <%s> %" SCIP_LONGINT_FORMAT ", possible new capacity %" SCIP_LONGINT_FORMAT ", offset of coefficients as big as capacity %d\n", gcd, rest, restweight, SCIPvarGetName(vars[candpos]), newweight, consdata->capacity - rest, offsetv); 9654 9655 /* must not change weights and capacity if one variable would be removed and we have a big coefficient, 9656 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0 9657 */ 9658 if( newweight == 0 && offsetv > 0 ) 9659 return SCIP_OKAY; 9660 9661 if( rest > 0 ) 9662 { 9663 /* replace old with new capacity */ 9664 consdata->capacity -= rest; 9665 ++(*nchgsides); 9666 9667 /* replace old big coefficients with new capacity */ 9668 for( v = 0; v < offsetv; ++v ) 9669 { 9670 consdataChgWeight(consdata, v, consdata->capacity); 9671 } 9672 9673 *nchgcoefs += offsetv; 9674 } 9675 9676 if( newweight == 0 ) 9677 { 9678 /* delete redundant coefficient */ 9679 SCIP_CALL( delCoefPos(scip, cons, candpos) ); 9680 assert(consdata->nvars == nvars - 1); 9681 --nvars; 9682 } 9683 else 9684 { 9685 /* replace old with new coefficient */ 9686 consdataChgWeight(consdata, candpos, newweight); 9687 } 9688 ++(*nchgcoefs); 9689 9690 assert(consdata->vars == vars); 9691 assert(consdata->nvars == nvars); 9692 assert(consdata->weights == weights); 9693 9694 CONTINUE: 9695 /* now constraint can be normalized, dividing it by the gcd */ 9696 for( v = nvars - 1; v >= 0; --v ) 9697 { 9698 consdataChgWeight(consdata, v, weights[v]/gcd); 9699 } 9700 (*nchgcoefs) += nvars; 9701 9702 consdata->capacity /= gcd; 9703 ++(*nchgsides); 9704 9705 SCIPdebugPrintCons(scip, cons, NULL); 9706 9707 SCIPdebugMsg(scip, "we did %d coefficient changes and %d side changes on constraint %s when applying one round of the gcd algorithm\n", *nchgcoefs - oldnchgcoefs, *nchgsides - oldnchgsides, SCIPconsGetName(cons)); 9708 } 9709 while( nvars >= 2 ); 9710 9711 return SCIP_OKAY; 9712 } 9713 9714 9715 /** inserts an element into the list of binary zero implications */ 9716 static 9717 SCIP_RETCODE insertZerolist( 9718 SCIP* scip, /**< SCIP data structure */ 9719 int** liftcands, /**< array of the lifting candidates */ 9720 int* nliftcands, /**< number of lifting candidates */ 9721 int** firstidxs, /**< array of first zeroitems indices */ 9722 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */ 9723 int** zeroitems, /**< pointer to zero items array */ 9724 int** nextidxs, /**< pointer to array of next zeroitems indeces */ 9725 int* zeroitemssize, /**< pointer to size of zero items array */ 9726 int* nzeroitems, /**< pointer to length of zero items array */ 9727 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */ 9728 SCIP_Bool value, /**< value v of variable y in implication */ 9729 int knapsackidx, /**< index of variable x in knapsack */ 9730 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */ 9731 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */ 9732 ) 9733 { 9734 int nzeros; 9735 9736 assert(liftcands != NULL); 9737 assert(liftcands[value] != NULL); 9738 assert(nliftcands != NULL); 9739 assert(firstidxs != NULL); 9740 assert(firstidxs[value] != NULL); 9741 assert(zeroweightsums != NULL); 9742 assert(zeroweightsums[value] != NULL); 9743 assert(zeroitems != NULL); 9744 assert(nextidxs != NULL); 9745 assert(zeroitemssize != NULL); 9746 assert(nzeroitems != NULL); 9747 assert(*nzeroitems <= *zeroitemssize); 9748 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip)); 9749 assert(memlimitreached != NULL); 9750 9751 nzeros = *nzeroitems; 9752 9753 /* allocate enough memory */ 9754 if( nzeros == *zeroitemssize ) 9755 { 9756 /* we explicitly construct the complete implication graph where the knapsack variables are involved; 9757 * this can be too huge - abort on memory limit 9758 */ 9759 if( *zeroitemssize >= MAX_ZEROITEMS_SIZE ) 9760 { 9761 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n", 9762 *zeroitemssize); 9763 *memlimitreached = TRUE; 9764 return SCIP_OKAY; 9765 } 9766 *zeroitemssize *= 2; 9767 *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE); 9768 SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) ); 9769 SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) ); 9770 } 9771 assert(nzeros < *zeroitemssize); 9772 9773 if( *memlimitreached ) 9774 *memlimitreached = FALSE; 9775 9776 /* insert element */ 9777 (*zeroitems)[nzeros] = knapsackidx; 9778 (*nextidxs)[nzeros] = firstidxs[value][probindex]; 9779 if( firstidxs[value][probindex] == 0 ) 9780 { 9781 liftcands[value][nliftcands[value]] = probindex; 9782 ++nliftcands[value]; 9783 } 9784 firstidxs[value][probindex] = nzeros; 9785 ++(*nzeroitems); 9786 zeroweightsums[value][probindex] += knapsackweight; 9787 9788 return SCIP_OKAY; 9789 } 9790 9791 #define MAX_CLIQUELENGTH 50 9792 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack: 9793 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}), 9794 * let cliqueweightsum(xi == v) := sum(W(C(xi == v))) 9795 * if cliqueweightsum(xi == v) < capacity: 9796 * - fixing variable xi to v would make the knapsack constraint redundant 9797 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same 9798 * redundancy effect: 9799 * wi' := capacity - cliqueweightsum(xi == v) 9800 * this rule can also be applied to binary variables not in the knapsack! 9801 */ 9802 static 9803 SCIP_RETCODE tightenWeightsLift( 9804 SCIP* scip, /**< SCIP data structure */ 9805 SCIP_CONS* cons, /**< knapsack constraint */ 9806 int* nchgcoefs, /**< pointer to count total number of changed coefficients */ 9807 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */ 9808 ) 9809 { 9810 SCIP_CONSDATA* consdata; 9811 SCIP_VAR** binvars; 9812 int nbinvars; 9813 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */ 9814 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */ 9815 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */ 9816 int* zeroitems; /* item number in knapsack that is implied to zero */ 9817 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */ 9818 int zeroitemssize; 9819 int nzeroitems; 9820 SCIP_Bool* zeroiteminserted[2]; 9821 SCIP_Bool memlimitreached; 9822 int nliftcands[2]; 9823 SCIP_Bool* cliqueused; 9824 SCIP_Bool* itemremoved; 9825 SCIP_Longint maxcliqueweightsum; 9826 SCIP_VAR** addvars; 9827 SCIP_Longint* addweights; 9828 SCIP_Longint addweightsum; 9829 int nvars; 9830 int cliquenum; 9831 int naddvars; 9832 int val; 9833 int i; 9834 9835 int* tmpindices; 9836 SCIP_Bool* tmpboolindices; 9837 int* tmpindices2; 9838 SCIP_Bool* tmpboolindices2; 9839 int* tmpindices3; 9840 SCIP_Bool* tmpboolindices3; 9841 int tmp; 9842 int tmp2; 9843 int tmp3; 9844 SCIP_CONSHDLR* conshdlr; 9845 SCIP_CONSHDLRDATA* conshdlrdata; 9846 9847 assert(nchgcoefs != NULL); 9848 assert(!SCIPconsIsModifiable(cons)); 9849 9850 consdata = SCIPconsGetData(cons); 9851 assert(consdata != NULL); 9852 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */ 9853 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */ 9854 assert(consdata->nvars > 0); 9855 assert(consdata->merged); 9856 9857 nvars = consdata->nvars; 9858 9859 /* check if the knapsack has too many items/cliques for applying this costly method */ 9860 if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE ) 9861 return SCIP_OKAY; 9862 9863 /* sort items, s.t. the heaviest one is in the first position */ 9864 sortItems(consdata); 9865 9866 if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE ) 9867 return SCIP_OKAY; 9868 9869 /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */ 9870 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip); 9871 assert(nbinvars > 0); 9872 binvars = SCIPgetVars(scip); 9873 9874 /* get conshdlrdata to use cleared memory */ 9875 conshdlr = SCIPconsGetHdlr(cons); 9876 assert(conshdlr != NULL); 9877 conshdlrdata = SCIPconshdlrGetData(conshdlr); 9878 assert(conshdlrdata != NULL); 9879 9880 /* allocate temporary memory for the list of implied to zero variables */ 9881 zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */ 9882 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) ); 9883 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) ); 9884 9885 assert(conshdlrdata->ints1size > 0); 9886 assert(conshdlrdata->ints2size > 0); 9887 assert(conshdlrdata->longints1size > 0); 9888 assert(conshdlrdata->longints2size > 0); 9889 9890 /* next if conditions should normally not be true, because it means that presolving has created more binary variables 9891 * than binary + integer variables existed at the presolving initialization method, but for example if you would 9892 * transform all integers into their binary representation then it maybe happens 9893 */ 9894 if( conshdlrdata->ints1size < nbinvars ) 9895 { 9896 int oldsize = conshdlrdata->ints1size; 9897 9898 conshdlrdata->ints1size = nbinvars; 9899 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) ); 9900 BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/ 9901 } 9902 if( conshdlrdata->ints2size < nbinvars ) 9903 { 9904 int oldsize = conshdlrdata->ints2size; 9905 9906 conshdlrdata->ints2size = nbinvars; 9907 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) ); 9908 BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/ 9909 } 9910 if( conshdlrdata->longints1size < nbinvars ) 9911 { 9912 int oldsize = conshdlrdata->longints1size; 9913 9914 conshdlrdata->longints1size = nbinvars; 9915 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) ); 9916 BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/ 9917 } 9918 if( conshdlrdata->longints2size < nbinvars ) 9919 { 9920 int oldsize = conshdlrdata->longints2size; 9921 9922 conshdlrdata->longints2size = nbinvars; 9923 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) ); 9924 BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/ 9925 } 9926 9927 firstidxs[0] = conshdlrdata->ints1; 9928 firstidxs[1] = conshdlrdata->ints2; 9929 zeroweightsums[0] = conshdlrdata->longints1; 9930 zeroweightsums[1] = conshdlrdata->longints2; 9931 9932 /* check for cleared arrays, all entries are zero */ 9933 #ifndef NDEBUG 9934 for( tmp = nbinvars - 1; tmp >= 0; --tmp ) 9935 { 9936 assert(firstidxs[0][tmp] == 0); 9937 assert(firstidxs[1][tmp] == 0); 9938 assert(zeroweightsums[0][tmp] == 0); 9939 assert(zeroweightsums[1][tmp] == 0); 9940 } 9941 #endif 9942 9943 SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) ); 9944 SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) ); 9945 9946 zeroitems[0] = -1; /* dummy element */ 9947 nextidxs[0] = -1; 9948 nzeroitems = 1; 9949 nliftcands[0] = 0; 9950 nliftcands[1] = 0; 9951 9952 assert(conshdlrdata->bools1size > 0); 9953 assert(conshdlrdata->bools2size > 0); 9954 9955 /* next if conditions should normally not be true, because it means that presolving has created more binary variables 9956 * than binary + integer variables existed at the presolving initialization method, but for example if you would 9957 * transform all integers into their binary representation then it maybe happens 9958 */ 9959 if( conshdlrdata->bools1size < nbinvars ) 9960 { 9961 int oldsize = conshdlrdata->bools1size; 9962 9963 conshdlrdata->bools1size = nbinvars; 9964 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) ); 9965 BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/ 9966 } 9967 if( conshdlrdata->bools2size < nbinvars ) 9968 { 9969 int oldsize = conshdlrdata->bools2size; 9970 9971 conshdlrdata->bools2size = nbinvars; 9972 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) ); 9973 BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/ 9974 } 9975 9976 zeroiteminserted[0] = conshdlrdata->bools1; 9977 zeroiteminserted[1] = conshdlrdata->bools2; 9978 9979 /* check for cleared arrays, all entries are zero */ 9980 #ifndef NDEBUG 9981 for( tmp = nbinvars - 1; tmp >= 0; --tmp ) 9982 { 9983 assert(zeroiteminserted[0][tmp] == 0); 9984 assert(zeroiteminserted[1][tmp] == 0); 9985 } 9986 #endif 9987 9988 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) ); 9989 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) ); 9990 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) ); 9991 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) ); 9992 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) ); 9993 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) ); 9994 9995 tmp2 = 0; 9996 tmp3 = 0; 9997 9998 memlimitreached = FALSE; 9999 for( i = 0; i < consdata->nvars && !memlimitreached; ++i ) 10000 { 10001 SCIP_CLIQUE** cliques; 10002 SCIP_VAR* var; 10003 SCIP_Longint weight; 10004 SCIP_Bool value; 10005 int varprobindex; 10006 int ncliques; 10007 int j; 10008 10009 tmp = 0; 10010 10011 /* get corresponding active problem variable */ 10012 var = consdata->vars[i]; 10013 weight = consdata->weights[i]; 10014 value = TRUE; 10015 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) ); 10016 varprobindex = SCIPvarGetProbindex(var); 10017 assert(0 <= varprobindex && varprobindex < nbinvars); 10018 10019 /* update the zeroweightsum */ 10020 zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/ 10021 tmpboolindices3[tmp3] = !value; 10022 tmpindices3[tmp3] = varprobindex; 10023 ++tmp3; 10024 10025 /* initialize the arrays of inserted zero items */ 10026 /* first add the implications (~x == 1 -> x == 0) */ 10027 { 10028 SCIP_Bool implvalue; 10029 int probindex; 10030 10031 probindex = SCIPvarGetProbindex(var); 10032 assert(0 <= probindex && probindex < nbinvars); 10033 10034 implvalue = !value; 10035 10036 /* insert the item into the list of the implied variable/value */ 10037 assert( !zeroiteminserted[implvalue][probindex] ); 10038 10039 if( firstidxs[implvalue][probindex] == 0 ) 10040 { 10041 tmpboolindices2[tmp2] = implvalue; 10042 tmpindices2[tmp2] = probindex; 10043 ++tmp2; 10044 } 10045 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums, 10046 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight, 10047 &memlimitreached) ); 10048 zeroiteminserted[implvalue][probindex] = TRUE; 10049 tmpboolindices[tmp] = implvalue; 10050 tmpindices[tmp] = probindex; 10051 ++tmp; 10052 } 10053 10054 /* get the cliques where the knapsack item is member of with value 1 */ 10055 ncliques = SCIPvarGetNCliques(var, value); 10056 cliques = SCIPvarGetCliques(var, value); 10057 for( j = 0; j < ncliques && !memlimitreached; ++j ) 10058 { 10059 SCIP_VAR** cliquevars; 10060 SCIP_Bool* cliquevalues; 10061 int ncliquevars; 10062 int k; 10063 10064 ncliquevars = SCIPcliqueGetNVars(cliques[j]); 10065 10066 /* discard big cliques */ 10067 if( ncliquevars > MAX_CLIQUELENGTH ) 10068 continue; 10069 10070 cliquevars = SCIPcliqueGetVars(cliques[j]); 10071 cliquevalues = SCIPcliqueGetValues(cliques[j]); 10072 10073 for( k = ncliquevars - 1; k >= 0; --k ) 10074 { 10075 SCIP_Bool implvalue; 10076 int probindex; 10077 10078 if( var == cliquevars[k] ) 10079 continue; 10080 10081 probindex = SCIPvarGetProbindex(cliquevars[k]); 10082 if( probindex == -1 ) 10083 continue; 10084 10085 assert(0 <= probindex && probindex < nbinvars); 10086 implvalue = cliquevalues[k]; 10087 10088 /* insert the item into the list of the clique variable/value */ 10089 if( !zeroiteminserted[implvalue][probindex] ) 10090 { 10091 if( firstidxs[implvalue][probindex] == 0 ) 10092 { 10093 tmpboolindices2[tmp2] = implvalue; 10094 tmpindices2[tmp2] = probindex; 10095 ++tmp2; 10096 } 10097 10098 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums, 10099 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight, 10100 &memlimitreached) ); 10101 zeroiteminserted[implvalue][probindex] = TRUE; 10102 tmpboolindices[tmp] = implvalue; 10103 tmpindices[tmp] = probindex; 10104 ++tmp; 10105 10106 if( memlimitreached ) 10107 break; 10108 } 10109 } 10110 } 10111 /* clear zeroiteminserted */ 10112 for( --tmp; tmp >= 0; --tmp) 10113 zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE; 10114 } 10115 SCIPfreeBufferArray(scip, &tmpboolindices); 10116 10117 /* calculate the clique partition and the maximal sum of weights using the clique information */ 10118 assert(consdata->sorted); 10119 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) ); 10120 10121 assert(conshdlrdata->bools3size > 0); 10122 10123 /* next if condition should normally not be true, because it means that presolving has created more binary variables 10124 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization 10125 * method, but for example if you would transform all integers into their binary representation then it maybe happens 10126 */ 10127 if( conshdlrdata->bools3size < consdata->nvars ) 10128 { 10129 int oldsize = conshdlrdata->bools3size; 10130 10131 conshdlrdata->bools3size = consdata->nvars;; 10132 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) ); 10133 BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/ 10134 } 10135 10136 cliqueused = conshdlrdata->bools3; 10137 10138 /* check for cleared array, all entries are zero */ 10139 #ifndef NDEBUG 10140 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp ) 10141 assert(cliqueused[tmp] == 0); 10142 #endif 10143 10144 maxcliqueweightsum = 0; 10145 tmp = 0; 10146 10147 /* calculates maximal weight of cliques */ 10148 for( i = 0; i < consdata->nvars; ++i ) 10149 { 10150 cliquenum = consdata->cliquepartition[i]; 10151 assert(0 <= cliquenum && cliquenum < consdata->nvars); 10152 10153 if( !cliqueused[cliquenum] ) 10154 { 10155 maxcliqueweightsum += consdata->weights[i]; 10156 cliqueused[cliquenum] = TRUE; 10157 tmpindices[tmp] = cliquenum; 10158 ++tmp; 10159 } 10160 } 10161 /* clear cliqueused */ 10162 for( --tmp; tmp >= 0; --tmp) 10163 cliqueused[tmp] = FALSE; 10164 10165 assert(conshdlrdata->bools4size > 0); 10166 10167 /* next if condition should normally not be true, because it means that presolving has created more binary variables 10168 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization 10169 * method, but for example if you would transform all integers into their binary representation then it maybe happens 10170 */ 10171 if( conshdlrdata->bools4size < consdata->nvars ) 10172 { 10173 int oldsize = conshdlrdata->bools4size; 10174 10175 conshdlrdata->bools4size = consdata->nvars; 10176 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) ); 10177 BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/ 10178 } 10179 10180 itemremoved = conshdlrdata->bools4; 10181 10182 /* check for cleared array, all entries are zero */ 10183 #ifndef NDEBUG 10184 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp ) 10185 assert(itemremoved[tmp] == 0); 10186 #endif 10187 10188 /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the 10189 * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be 10190 * included in subsequent cliqueweightsum calculations) 10191 */ 10192 SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) ); 10193 SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) ); 10194 naddvars = 0; 10195 addweightsum = 0; 10196 for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val ) 10197 { 10198 for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i ) 10199 { 10200 SCIP_Longint cliqueweightsum; 10201 int probindex; 10202 int idx; 10203 int j; 10204 10205 tmp = 0; 10206 10207 probindex = liftcands[val][i]; 10208 assert(0 <= probindex && probindex < nbinvars); 10209 10210 /* ignore empty zero lists and variables that cannot be lifted anyways */ 10211 if( firstidxs[val][probindex] == 0 10212 || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity ) 10213 continue; 10214 10215 /* mark the items that are implied to zero by setting the current variable to the current value */ 10216 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] ) 10217 { 10218 assert(0 < idx && idx < nzeroitems); 10219 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars); 10220 itemremoved[zeroitems[idx]] = TRUE; 10221 } 10222 10223 /* calculate the residual cliqueweight sum */ 10224 cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */ 10225 for( j = 0; j < consdata->nvars; ++j ) 10226 { 10227 cliquenum = consdata->cliquepartition[j]; 10228 assert(0 <= cliquenum && cliquenum < consdata->nvars); 10229 if( !itemremoved[j] ) 10230 { 10231 if( !cliqueused[cliquenum] ) 10232 { 10233 cliqueweightsum += consdata->weights[j]; 10234 cliqueused[cliquenum] = TRUE; 10235 tmpindices[tmp] = cliquenum; 10236 ++tmp; 10237 } 10238 10239 if( cliqueweightsum >= consdata->capacity ) 10240 break; 10241 } 10242 } 10243 10244 /* check if the weight of the variable/value can be increased */ 10245 if( cliqueweightsum < consdata->capacity ) 10246 { 10247 SCIP_VAR* var; 10248 SCIP_Longint weight; 10249 10250 /* insert the variable (with value TRUE) in the list of additional items */ 10251 assert(naddvars < 2*nbinvars); 10252 var = binvars[probindex]; 10253 if( val == FALSE ) 10254 { 10255 SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) ); 10256 } 10257 weight = consdata->capacity - cliqueweightsum; 10258 addvars[naddvars] = var; 10259 addweights[naddvars] = weight; 10260 addweightsum += weight; 10261 naddvars++; 10262 10263 SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n", 10264 SCIPconsGetName(cons), weight, SCIPvarGetName(var)); 10265 } 10266 10267 /* clear itemremoved */ 10268 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] ) 10269 { 10270 assert(0 < idx && idx < nzeroitems); 10271 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars); 10272 itemremoved[zeroitems[idx]] = FALSE; 10273 } 10274 /* clear cliqueused */ 10275 for( --tmp; tmp >= 0; --tmp) 10276 cliqueused[tmpindices[tmp]] = FALSE; 10277 } 10278 } 10279 10280 /* clear part of zeroweightsums */ 10281 for( --tmp3; tmp3 >= 0; --tmp3) 10282 zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0; 10283 10284 /* clear rest of zeroweightsums and firstidxs */ 10285 for( --tmp2; tmp2 >= 0; --tmp2) 10286 { 10287 zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0; 10288 firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0; 10289 } 10290 10291 /* add all additional item weights */ 10292 for( i = 0; i < naddvars; ++i ) 10293 { 10294 SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) ); 10295 } 10296 *nchgcoefs += naddvars; 10297 10298 if( naddvars > 0 ) 10299 { 10300 /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */ 10301 SCIP_CALL( mergeMultiples(scip, cons, cutoff) ); 10302 } 10303 10304 /* free temporary memory */ 10305 SCIPfreeBufferArray(scip, &addweights); 10306 SCIPfreeBufferArray(scip, &addvars); 10307 SCIPfreeBufferArray(scip, &tmpindices); 10308 SCIPfreeBufferArray(scip, &tmpindices2); 10309 SCIPfreeBufferArray(scip, &tmpindices3); 10310 SCIPfreeBufferArray(scip, &tmpboolindices2); 10311 SCIPfreeBufferArray(scip, &tmpboolindices3); 10312 SCIPfreeBufferArray(scip, &nextidxs); 10313 SCIPfreeBufferArray(scip, &zeroitems); 10314 SCIPfreeBufferArray(scip, &liftcands[1]); 10315 SCIPfreeBufferArray(scip, &liftcands[0]); 10316 10317 return SCIP_OKAY; 10318 } 10319 10320 /** tightens item weights and capacity in presolving: 10321 * given a knapsack sum(wi*xi) <= capacity 10322 * (1) let weightsum := sum(wi) 10323 * if weightsum - wi < capacity: 10324 * - not using item i would make the knapsack constraint redundant 10325 * - wi and capacity can be changed to have the same redundancy effect and the same results for 10326 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation 10327 * - change coefficients: 10328 * wi' := weightsum - capacity 10329 * capacity' := capacity - (wi - wi') 10330 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight 10331 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order 10332 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), 10333 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there 10334 * can be multiple times the same weight, this can be improved 10335 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big 10336 * weight, to capacity - lastmininmalweightsum, e.g. : 10337 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 10338 * -> minimal weightsums: 5, 5, 10, 10 10339 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19 10340 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in 10341 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19 10342 * (3) let W(C) be the maximal weight of clique C, 10343 * cliqueweightsum := sum(W(C)) 10344 * if cliqueweightsum - W(C) < capacity: 10345 * - not using any item of C would make the knapsack constraint redundant 10346 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for 10347 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation 10348 * - change coefficients: 10349 * delta := capacity - (cliqueweightsum - W(C)) 10350 * wi' := max(wi - delta, 0) 10351 * capacity' := capacity - delta 10352 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might 10353 * introduce infeasible solutions. 10354 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}), 10355 * let cliqueweightsum(xi == v) := sum(W(C(xi == v))) 10356 * if cliqueweightsum(xi == v) < capacity: 10357 * - fixing variable xi to v would make the knapsack constraint redundant 10358 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same 10359 * redundancy effect: 10360 * wi' := capacity - cliqueweightsum(xi == v) 10361 * This rule can also be applied to binary variables not in the knapsack! 10362 * (5) if min{w} + wi > capacity: 10363 * - using item i would force to fix other items to zero 10364 * - wi can be increased to the capacity 10365 */ 10366 static 10367 SCIP_RETCODE tightenWeights( 10368 SCIP* scip, /**< SCIP data structure */ 10369 SCIP_CONS* cons, /**< knapsack constraint */ 10370 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */ 10371 int* nchgcoefs, /**< pointer to count total number of changed coefficients */ 10372 int* nchgsides, /**< pointer to count number of side changes */ 10373 int* naddconss, /**< pointer to count number of added constraints */ 10374 int* ndelconss, /**< pointer to count number of deleted constraints */ 10375 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */ 10376 ) 10377 { 10378 SCIP_CONSHDLRDATA* conshdlrdata; 10379 SCIP_CONSDATA* consdata; 10380 SCIP_Longint* weights; 10381 SCIP_Longint sumcoef; 10382 SCIP_Longint capacity; 10383 SCIP_Longint newweight; 10384 SCIP_Longint maxweight; 10385 SCIP_Longint minweight; 10386 SCIP_Bool sumcoefcase = FALSE; 10387 int startpos; 10388 int backpos; 10389 int nvars; 10390 int pos; 10391 int k; 10392 int i; 10393 10394 assert(nchgcoefs != NULL); 10395 assert(nchgsides != NULL); 10396 assert(!SCIPconsIsModifiable(cons)); 10397 10398 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons)); 10399 assert(conshdlrdata != NULL); 10400 10401 consdata = SCIPconsGetData(cons); 10402 assert(consdata != NULL); 10403 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */ 10404 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */ 10405 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */ 10406 assert(consdata->nvars > 0); 10407 10408 SCIP_CALL( mergeMultiples(scip, cons, cutoff) ); 10409 if( *cutoff ) 10410 return SCIP_OKAY; 10411 10412 /* apply rule (1) */ 10413 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 ) 10414 { 10415 do 10416 { 10417 assert(consdata->merged); 10418 10419 /* sort items, s.t. the heaviest one is in the first position */ 10420 sortItems(consdata); 10421 10422 for( i = 0; i < consdata->nvars; ++i ) 10423 { 10424 SCIP_Longint weight; 10425 10426 weight = consdata->weights[i]; 10427 if( consdata->weightsum - weight < consdata->capacity ) 10428 { 10429 newweight = consdata->weightsum - consdata->capacity; 10430 consdataChgWeight(consdata, i, newweight); 10431 consdata->capacity -= (weight - newweight); 10432 (*nchgcoefs)++; 10433 (*nchgsides)++; 10434 assert(!consdata->sorted); 10435 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT ", capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n", 10436 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight, 10437 consdata->capacity + (weight-newweight), consdata->capacity); 10438 } 10439 else 10440 break; 10441 } 10442 } 10443 while( !consdata->sorted && consdata->weightsum > consdata->capacity ); 10444 } 10445 10446 /* check for redundancy */ 10447 if( consdata->weightsum <= consdata->capacity ) 10448 return SCIP_OKAY; 10449 10450 pos = 0; 10451 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity ) 10452 ++pos; 10453 10454 sumcoef = 0; 10455 weights = consdata->weights; 10456 nvars = consdata->nvars; 10457 capacity = consdata->capacity; 10458 10459 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 && 10460 pos < nvars && weights[pos] + weights[pos + 1] > capacity ) 10461 { 10462 /* further reductions using the next possible coefficient sum 10463 * 10464 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19 10465 */ 10466 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */ 10467 for( k = 0; k < 4; ++k ) 10468 { 10469 newweight = capacity - sumcoef; 10470 10471 /* determine next minimal coefficient sum */ 10472 switch( k ) 10473 { 10474 case 0: 10475 sumcoef = weights[nvars - 1]; 10476 backpos = nvars - 1; 10477 break; 10478 case 1: 10479 sumcoef = weights[nvars - 2]; 10480 backpos = nvars - 2; 10481 break; 10482 case 2: 10483 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] ) 10484 { 10485 sumcoefcase = TRUE; 10486 sumcoef = weights[nvars - 3]; 10487 backpos = nvars - 3; 10488 } 10489 else 10490 { 10491 sumcoefcase = FALSE; 10492 sumcoef = weights[nvars - 1] + weights[nvars - 2]; 10493 backpos = nvars - 2; 10494 } 10495 break; 10496 default: 10497 assert(k == 3); 10498 if( sumcoefcase ) 10499 { 10500 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] ) 10501 { 10502 sumcoef = weights[nvars - 4]; 10503 backpos = nvars - 4; 10504 } 10505 else 10506 { 10507 sumcoef = weights[nvars - 1] + weights[nvars - 2]; 10508 backpos = nvars - 2; 10509 } 10510 } 10511 else 10512 { 10513 sumcoef = weights[nvars - 3]; 10514 backpos = nvars - 3; 10515 } 10516 break; 10517 } 10518 10519 if( backpos <= pos ) 10520 break; 10521 10522 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */ 10523 maxweight = weights[pos]; 10524 startpos = pos; 10525 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity ) 10526 { 10527 assert(newweight > weights[pos]); 10528 10529 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n", 10530 SCIPconsGetName(cons), maxweight, newweight); 10531 10532 consdataChgWeight(consdata, pos, newweight); 10533 10534 ++pos; 10535 assert(pos < nvars); 10536 10537 maxweight = weights[pos]; 10538 10539 if( backpos <= pos ) 10540 break; 10541 } 10542 (*nchgcoefs) += (pos - startpos); 10543 10544 /* skip unchangable weights */ 10545 while( pos < nvars && weights[pos] + sumcoef == capacity ) 10546 ++pos; 10547 10548 /* check special case were there is only one weight left to tighten 10549 * 10550 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36) 10551 * 10552 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95 10553 * 10554 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further) 10555 */ 10556 if( pos + 1 == backpos && weights[pos] > sumcoef && 10557 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) ) 10558 { 10559 newweight = capacity - sumcoef; 10560 assert(newweight > weights[pos]); 10561 10562 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n", 10563 SCIPconsGetName(cons), maxweight, newweight); 10564 10565 consdataChgWeight(consdata, pos, newweight); 10566 10567 break; 10568 } 10569 10570 if( backpos <= pos ) 10571 break; 10572 } 10573 } 10574 10575 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */ 10576 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 ) 10577 { 10578 if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 && 10579 pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity && 10580 consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) ) 10581 { 10582 SCIP_VAR** clqvars; 10583 SCIP_CONS* cliquecons; 10584 char name[SCIP_MAXSTRLEN]; 10585 int* clqpart; 10586 int nclqvars; 10587 int nclq; 10588 int len; 10589 int c; 10590 int w; 10591 10592 assert(!SCIPconsIsDeleted(cons)); 10593 10594 if( pos == consdata->nvars ) 10595 { 10596 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons)); 10597 10598 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars, 10599 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 10600 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 10601 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), 10602 SCIPconsIsStickingAtNode(cons)) ); 10603 10604 SCIP_CALL( SCIPaddCons(scip, cliquecons) ); 10605 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) ); 10606 ++(*naddconss); 10607 10608 /* delete old constraint */ 10609 SCIP_CALL( SCIPdelCons(scip, cons) ); 10610 ++(*ndelconss); 10611 10612 return SCIP_OKAY; 10613 } 10614 10615 len = consdata->nvars - pos; 10616 10617 /* allocate temporary memory */ 10618 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) ); 10619 10620 /* calculate clique partition */ 10621 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) ); 10622 assert(nclq <= len); 10623 10624 #ifndef NDEBUG 10625 /* clique numbers must be at least as high as the index */ 10626 for( w = 0; w < nclq; ++w ) 10627 assert(clqpart[w] <= w); 10628 #endif 10629 10630 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons)); 10631 10632 /* allocate temporary memory */ 10633 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) ); 10634 10635 /* copy corresponding variables with big coefficients */ 10636 for( w = pos - 1; w >= 0; --w ) 10637 clqvars[w] = consdata->vars[w]; 10638 10639 /* create for each clique a set-packing constraint */ 10640 for( c = 0; c < nclq; ++c ) 10641 { 10642 nclqvars = pos; 10643 10644 for( w = c; w < len; ++w ) 10645 { 10646 if( clqpart[w] == c ) 10647 { 10648 assert(nclqvars < pos + len - nclq + 1); 10649 clqvars[nclqvars] = consdata->vars[w + pos]; 10650 ++nclqvars; 10651 } 10652 } 10653 10654 assert(nclqvars > 1); 10655 10656 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c); 10657 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars, 10658 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 10659 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 10660 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), 10661 SCIPconsIsStickingAtNode(cons)) ); 10662 SCIPdebugMsg(scip, " -> adding clique constraint: "); 10663 SCIPdebugPrintCons(scip, cliquecons, NULL); 10664 SCIP_CALL( SCIPaddCons(scip, cliquecons) ); 10665 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) ); 10666 ++(*naddconss); 10667 } 10668 10669 /* delete old constraint */ 10670 SCIP_CALL( SCIPdelCons(scip, cons) ); 10671 ++(*ndelconss); 10672 10673 SCIPfreeBufferArray(scip, &clqvars); 10674 SCIPfreeBufferArray(scip, &clqpart); 10675 10676 return SCIP_OKAY; 10677 } 10678 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) ) 10679 { 10680 SCIP_Longint* maxcliqueweights; 10681 SCIP_Longint* newweightvals; 10682 int* newweightidxs; 10683 SCIP_Longint cliqueweightsum; 10684 10685 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) ); 10686 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) ); 10687 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) ); 10688 10689 /* repeat as long as changes have been applied */ 10690 do 10691 { 10692 int ncliques; 10693 int cliquenum; 10694 SCIP_Bool zeroweights; 10695 10696 assert(consdata->merged); 10697 10698 /* sort items, s.t. the heaviest one is in the first position */ 10699 sortItems(consdata); 10700 10701 /* calculate a clique partition */ 10702 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) ); 10703 10704 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */ 10705 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 ) 10706 break; 10707 10708 /* calculate the maximal weight of the cliques and store the clique type */ 10709 cliqueweightsum = 0; 10710 ncliques = 0; 10711 10712 for( i = 0; i < consdata->nvars; ++i ) 10713 { 10714 SCIP_Longint weight; 10715 10716 cliquenum = consdata->cliquepartition[i]; 10717 assert(0 <= cliquenum && cliquenum <= ncliques); 10718 10719 weight = consdata->weights[i]; 10720 assert(weight > 0); 10721 10722 if( cliquenum == ncliques ) 10723 { 10724 maxcliqueweights[ncliques] = weight; 10725 cliqueweightsum += weight; 10726 ++ncliques; 10727 } 10728 10729 assert(maxcliqueweights[cliquenum] >= weight); 10730 } 10731 10732 /* apply rule on every clique */ 10733 zeroweights = FALSE; 10734 for( i = 0; i < ncliques; ++i ) 10735 { 10736 SCIP_Longint delta; 10737 10738 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]); 10739 if( delta > 0 ) 10740 { 10741 SCIP_Longint newcapacity; 10742 #ifndef NDEBUG 10743 SCIP_Longint newmincliqueweight; 10744 #endif 10745 SCIP_Longint newminweightsuminclique; 10746 SCIP_Bool forceclique; 10747 int nnewweights; 10748 int j; 10749 10750 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", 10751 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta); 10752 newcapacity = consdata->capacity - delta; 10753 forceclique = FALSE; 10754 nnewweights = 0; 10755 #ifndef NDEBUG 10756 newmincliqueweight = newcapacity + 1; 10757 for( j = 0; j < i; ++j ) 10758 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */ 10759 #endif 10760 for( j = i; j < consdata->nvars; ++j ) 10761 { 10762 if( consdata->cliquepartition[j] == i ) 10763 { 10764 newweight = consdata->weights[j] - delta; 10765 newweight = MAX(newweight, 0); 10766 10767 /* cache the new weight */ 10768 assert(nnewweights < consdata->nvars); 10769 newweightvals[nnewweights] = newweight; 10770 newweightidxs[nnewweights] = j; 10771 nnewweights++; 10772 10773 #ifndef NDEBUG 10774 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */ 10775 newmincliqueweight = newweight; 10776 #endif 10777 } 10778 } 10779 10780 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */ 10781 if( nnewweights > 1 ) 10782 { 10783 #ifndef NDEBUG 10784 j = newweightidxs[nnewweights - 2]; 10785 assert(0 <= j && j < consdata->nvars); 10786 assert(consdata->cliquepartition[j] == i); 10787 j = newweightidxs[nnewweights - 1]; 10788 assert(0 <= j && j < consdata->nvars); 10789 assert(consdata->cliquepartition[j] == i); 10790 #endif 10791 10792 newminweightsuminclique = newweightvals[nnewweights - 2]; 10793 newminweightsuminclique += newweightvals[nnewweights - 1]; 10794 10795 /* check if these new two minimal weights both fit into the knapsack; 10796 * if this is true, we have to add a clique constraint in order to enforce the clique 10797 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight 10798 * reduction might be infeasible, i.e., allows additional solutions) 10799 */ 10800 if( newminweightsuminclique <= newcapacity ) 10801 forceclique = TRUE; 10802 } 10803 10804 /* check if we really want to apply the change */ 10805 if( conshdlrdata->disaggregation || !forceclique ) 10806 { 10807 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n", 10808 consdata->capacity, newcapacity, forceclique); 10809 consdata->capacity = newcapacity; 10810 (*nchgsides)++; 10811 10812 for( k = 0; k < nnewweights; ++k ) 10813 { 10814 j = newweightidxs[k]; 10815 assert(0 <= j && j < consdata->nvars); 10816 assert(consdata->cliquepartition[j] == i); 10817 10818 /* apply the weight change */ 10819 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n", 10820 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]); 10821 consdataChgWeight(consdata, j, newweightvals[k]); 10822 (*nchgcoefs)++; 10823 assert(!consdata->sorted); 10824 zeroweights = zeroweights || (newweightvals[k] == 0); 10825 } 10826 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits, 10827 * we have to make sure, the clique is enforced - the clique might have been constructed partially from 10828 * this constraint, and by reducing the weights, this clique information is not contained anymore in the 10829 * knapsack constraint 10830 */ 10831 if( forceclique ) 10832 { 10833 SCIP_CONS* cliquecons; 10834 char name[SCIP_MAXSTRLEN]; 10835 SCIP_VAR** cliquevars; 10836 10837 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) ); 10838 for( k = 0; k < nnewweights; ++k ) 10839 cliquevars[k] = consdata->vars[newweightidxs[k]]; 10840 10841 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i); 10842 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars, 10843 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 10844 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), 10845 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), 10846 SCIPconsIsStickingAtNode(cons)) ); 10847 SCIPdebugMsg(scip, " -> adding clique constraint: "); 10848 SCIPdebugPrintCons(scip, cliquecons, NULL); 10849 SCIP_CALL( SCIPaddCons(scip, cliquecons) ); 10850 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) ); 10851 SCIPfreeBufferArray(scip, &cliquevars); 10852 (*naddconss)++; 10853 } 10854 } 10855 } 10856 } 10857 if( zeroweights ) 10858 { 10859 SCIP_CALL( removeZeroWeights(scip, cons) ); 10860 } 10861 } 10862 while( !consdata->sorted && consdata->weightsum > consdata->capacity ); 10863 10864 /* free temporary memory */ 10865 SCIPfreeBufferArray(scip, &newweightidxs); 10866 SCIPfreeBufferArray(scip, &newweightvals); 10867 SCIPfreeBufferArray(scip, &maxcliqueweights); 10868 10869 /* check for redundancy */ 10870 if( consdata->weightsum <= consdata->capacity ) 10871 return SCIP_OKAY; 10872 } 10873 } 10874 10875 /* apply rule (3) */ 10876 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 ) 10877 { 10878 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) ); 10879 } 10880 10881 /* check for redundancy */ 10882 if( consdata->weightsum <= consdata->capacity ) 10883 return SCIP_OKAY; 10884 10885 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 ) 10886 { 10887 /* apply rule (4) (all but smallest weight) */ 10888 assert(consdata->merged); 10889 sortItems(consdata); 10890 minweight = consdata->weights[consdata->nvars-1]; 10891 for( i = 0; i < consdata->nvars-1; ++i ) 10892 { 10893 SCIP_Longint weight; 10894 10895 weight = consdata->weights[i]; 10896 assert(weight >= minweight); 10897 if( minweight + weight > consdata->capacity ) 10898 { 10899 if( weight < consdata->capacity ) 10900 { 10901 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n", 10902 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity); 10903 assert(consdata->sorted); 10904 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */ 10905 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]); 10906 consdata->sorted = TRUE; 10907 (*nchgcoefs)++; 10908 } 10909 } 10910 else 10911 break; 10912 } 10913 10914 /* apply rule (5) (smallest weight) */ 10915 if( consdata->nvars >= 2 ) 10916 { 10917 SCIP_Longint weight; 10918 10919 minweight = consdata->weights[consdata->nvars-2]; 10920 weight = consdata->weights[consdata->nvars-1]; 10921 assert(minweight >= weight); 10922 if( minweight + weight > consdata->capacity && weight < consdata->capacity ) 10923 { 10924 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n", 10925 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity); 10926 assert(consdata->sorted); 10927 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */ 10928 assert(minweight >= consdata->weights[consdata->nvars-1]); 10929 consdata->sorted = TRUE; 10930 (*nchgcoefs)++; 10931 } 10932 } 10933 } 10934 10935 return SCIP_OKAY; 10936 } 10937 10938 10939 #ifdef SCIP_DEBUG 10940 static 10941 void printClique( 10942 SCIP_VAR** cliquevars, 10943 int ncliquevars 10944 ) 10945 { 10946 int b; 10947 SCIPdebugMessage("adding new Clique: "); 10948 for( b = 0; b < ncliquevars; ++b ) 10949 SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b])); 10950 SCIPdebugPrintf("\n"); 10951 } 10952 #endif 10953 10954 /** adds negated cliques of the knapsack constraint to the global clique table */ 10955 static 10956 SCIP_RETCODE addNegatedCliques( 10957 SCIP*const scip, /**< SCIP data structure */ 10958 SCIP_CONS*const cons, /**< knapsack constraint */ 10959 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */ 10960 int*const nbdchgs /**< pointer to count the number of performed bound changes */ 10961 ) 10962 { 10963 SCIP_CONSDATA* consdata; 10964 SCIP_CONSHDLRDATA* conshdlrdata; 10965 SCIP_VAR** poscliquevars; 10966 SCIP_VAR** cliquevars; 10967 SCIP_Longint* maxweights; 10968 SCIP_Longint* gainweights; 10969 int* gaincliquepartition; 10970 SCIP_Bool* cliqueused; 10971 SCIP_Longint minactduetonegcliques; 10972 SCIP_Longint freecapacity; 10973 SCIP_Longint lastweight; 10974 SCIP_Longint beforelastweight; 10975 int nposcliquevars; 10976 int ncliquevars; 10977 int nvars; 10978 int nnegcliques; 10979 int lastcliqueused; 10980 int thisnbdchgs; 10981 int v; 10982 int w; 10983 10984 assert(scip != NULL); 10985 assert(cons != NULL); 10986 assert(cutoff != NULL); 10987 assert(nbdchgs != NULL); 10988 10989 *cutoff = FALSE; 10990 10991 consdata = SCIPconsGetData(cons); 10992 assert(consdata != NULL); 10993 10994 nvars = consdata->nvars; 10995 10996 /* check whether the cliques have already been added */ 10997 if( consdata->cliquesadded || nvars == 0 ) 10998 return SCIP_OKAY; 10999 11000 /* make sure, the items are merged */ 11001 SCIP_CALL( mergeMultiples(scip, cons, cutoff) ); 11002 if( *cutoff ) 11003 return SCIP_OKAY; 11004 11005 /* make sure, items are sorted by non-increasing weight */ 11006 sortItems(consdata); 11007 11008 assert(consdata->merged); 11009 11010 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons)); 11011 assert(conshdlrdata != NULL); 11012 11013 /* calculate a clique partition */ 11014 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) ); 11015 nnegcliques = consdata->nnegcliques; 11016 11017 /* if we have no negated cliques, stop */ 11018 if( nnegcliques == nvars ) 11019 return SCIP_OKAY; 11020 11021 /* get temporary memory */ 11022 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) ); 11023 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) ); 11024 SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) ); 11025 SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) ); 11026 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) ); 11027 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) ); 11028 11029 nnegcliques = 0; 11030 minactduetonegcliques = 0; 11031 11032 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */ 11033 for( v = 0; v < nvars; ++v ) 11034 { 11035 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques); 11036 assert(consdata->weights[v] > 0); 11037 11038 if( consdata->negcliquepartition[v] == nnegcliques ) 11039 { 11040 nnegcliques++; 11041 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v]; 11042 } 11043 else 11044 minactduetonegcliques += consdata->weights[v]; 11045 } 11046 11047 nposcliquevars = 0; 11048 11049 /* add cliques, using negated cliques information */ 11050 if( minactduetonegcliques > 0 ) 11051 { 11052 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */ 11053 freecapacity = consdata->capacity - minactduetonegcliques; 11054 11055 SCIPdebugPrintCons(scip, cons, NULL); 11056 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", 11057 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity); 11058 11059 /* calculate possible gain by switching chosen items in negated cliques */ 11060 for( v = 0; v < nvars; ++v ) 11061 { 11062 if( !cliqueused[consdata->negcliquepartition[v]] ) 11063 { 11064 cliqueused[consdata->negcliquepartition[v]] = TRUE; 11065 for( w = v + 1; w < nvars; ++w ) 11066 { 11067 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of 11068 * weight[w] (which are both in a negated clique) */ 11069 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w] 11070 && consdata->weights[v] > consdata->weights[w] ) 11071 { 11072 poscliquevars[nposcliquevars] = consdata->vars[w]; 11073 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w]; 11074 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v]; 11075 ++nposcliquevars; 11076 } 11077 } 11078 } 11079 } 11080 11081 /* try to create negated cliques */ 11082 if( nposcliquevars > 0 ) 11083 { 11084 /* sort possible gain per substitution of the clique members */ 11085 SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars); 11086 11087 for( v = 0; v < nposcliquevars; ++v ) 11088 { 11089 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) ); 11090 ncliquevars = 1; 11091 lastweight = gainweights[v]; 11092 beforelastweight = -1; 11093 lastcliqueused = gaincliquepartition[v]; 11094 /* clear cliqueused to get an unused array */ 11095 BMSclearMemoryArray(cliqueused, nnegcliques); 11096 cliqueused[gaincliquepartition[v]] = TRUE; 11097 11098 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not 11099 * in the same negated clique and by taking two of them would exceed the free capacity */ 11100 for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w ) 11101 { 11102 beforelastweight = lastweight; 11103 lastweight = gainweights[w]; 11104 lastcliqueused = gaincliquepartition[w]; 11105 cliqueused[gaincliquepartition[w]] = TRUE; 11106 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) ); 11107 ++ncliquevars; 11108 } 11109 11110 if( ncliquevars > 1 ) 11111 { 11112 SCIPdebug( printClique(cliquevars, ncliquevars) ); 11113 assert(beforelastweight > 0); 11114 /* add the clique to the clique table */ 11115 /* this really happens, e.g., on enigma.mps from the short test set */ 11116 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) ); 11117 if( *cutoff ) 11118 goto TERMINATE; 11119 *nbdchgs += thisnbdchgs; 11120 11121 /* reset last used clique to get slightly different cliques */ 11122 cliqueused[lastcliqueused] = FALSE; 11123 11124 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */ 11125 for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w ) 11126 { 11127 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) ); 11128 SCIPdebug( printClique(cliquevars, ncliquevars) ); 11129 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) ); 11130 if( *cutoff ) 11131 goto TERMINATE; 11132 *nbdchgs += thisnbdchgs; 11133 } 11134 } 11135 } 11136 } 11137 } 11138 11139 TERMINATE: 11140 /* free temporary memory */ 11141 SCIPfreeBufferArray(scip, &cliqueused); 11142 SCIPfreeBufferArray(scip, &maxweights); 11143 SCIPfreeBufferArray(scip, &gaincliquepartition); 11144 SCIPfreeBufferArray(scip, &gainweights); 11145 SCIPfreeBufferArray(scip, &cliquevars); 11146 SCIPfreeBufferArray(scip, &poscliquevars); 11147 11148 return SCIP_OKAY; 11149 } 11150 11151 /** greedy clique detection by considering weights and capacity 11152 * 11153 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily 11154 * 1) neighboring items which exceed the capacity together => one clique 11155 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques 11156 */ 11157 static 11158 SCIP_RETCODE greedyCliqueAlgorithm( 11159 SCIP*const scip, /**< SCIP data structure */ 11160 SCIP_VAR** items, /**< array of variable items */ 11161 SCIP_Longint* weights, /**< weights of the items */ 11162 int nitems, /**< the number of items */ 11163 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */ 11164 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */ 11165 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */ 11166 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */ 11167 int*const nbdchgs /**< pointer to count the number of performed bound changes */ 11168 ) 11169 { 11170 SCIP_Longint lastweight; 11171 int ncliquevars; 11172 int i; 11173 int thisnbdchgs; 11174 11175 if( nitems <= 1 ) 11176 return SCIP_OKAY; 11177 11178 /* sort possible gain per substitution of the clique members */ 11179 if( ! sorteditems ) 11180 SCIPsortDownLongPtr(weights,(void**) items, nitems); 11181 11182 ncliquevars = 1; 11183 lastweight = weights[0]; 11184 11185 /* taking these two weights together violates the knapsack => include into clique */ 11186 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i ) 11187 { 11188 lastweight = weights[i]; 11189 ++ncliquevars; 11190 } 11191 11192 if( ncliquevars > 1 ) 11193 { 11194 SCIP_Longint compareweight; 11195 SCIP_VAR** cliquevars; 11196 int compareweightidx; 11197 int minclqsize; 11198 int nnzadded; 11199 11200 /* add the clique to the clique table */ 11201 SCIPdebug( printClique(items, ncliquevars) ); 11202 SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) ); 11203 11204 if( *cutoff ) 11205 return SCIP_OKAY; 11206 11207 *nbdchgs += thisnbdchgs; 11208 nnzadded = ncliquevars; 11209 11210 /* 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)*/ 11211 if( ncliquevars == nitems ) 11212 return SCIP_OKAY; 11213 11214 /* copy items in order into buffer array and deduce more cliques */ 11215 SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) ); 11216 11217 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */ 11218 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */ 11219 compareweightidx = ncliquevars - 2; 11220 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity); 11221 11222 /* determine minimum clique size for the following loop */ 11223 minclqsize = (int)(cliqueextractfactor * ncliquevars); 11224 minclqsize = MAX(minclqsize, 2); 11225 11226 /* loop over the remaining variables and the larger items of the first clique until we 11227 * find another clique or reach the size limit */ 11228 while( compareweightidx >= 0 && i < nitems && ! (*cutoff) 11229 && ncliquevars >= minclqsize /* stop at a given minimum clique size */ 11230 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */ 11231 ) 11232 { 11233 compareweight = weights[compareweightidx]; 11234 assert(compareweight > 0); 11235 11236 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */ 11237 if( compareweight + weights[i] > capacity ) 11238 { 11239 assert(compareweightidx == ncliquevars -2); 11240 cliquevars[ncliquevars - 1] = items[i]; 11241 SCIPdebug( printClique(cliquevars, ncliquevars) ); 11242 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) ); 11243 11244 nnzadded += ncliquevars; 11245 11246 /* stop when there is a cutoff */ 11247 if( ! (*cutoff) ) 11248 *nbdchgs += thisnbdchgs; 11249 11250 /* go to next smaller item */ 11251 ++i; 11252 } 11253 else 11254 { 11255 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */ 11256 compareweightidx--; 11257 ncliquevars --; 11258 } 11259 } 11260 11261 SCIPfreeBufferArray(scip, &cliquevars); 11262 } 11263 11264 return SCIP_OKAY; 11265 } 11266 11267 /** adds cliques of the knapsack constraint to the global clique table */ 11268 static 11269 SCIP_RETCODE addCliques( 11270 SCIP*const scip, /**< SCIP data structure */ 11271 SCIP_CONS*const cons, /**< knapsack constraint */ 11272 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */ 11273 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */ 11274 int*const nbdchgs /**< pointer to count the number of performed bound changes */ 11275 ) 11276 { 11277 SCIP_CONSDATA* consdata; 11278 SCIP_CONSHDLRDATA* conshdlrdata; 11279 int i; 11280 SCIP_Longint minactduetonegcliques; 11281 SCIP_Longint freecapacity; 11282 int nnegcliques; 11283 int cliquenum; 11284 SCIP_VAR** poscliquevars; 11285 SCIP_Longint* gainweights; 11286 int nposcliquevars; 11287 SCIP_Longint* secondmaxweights; 11288 int nvars; 11289 11290 assert(scip != NULL); 11291 assert(cons != NULL); 11292 assert(cutoff != NULL); 11293 assert(nbdchgs != NULL); 11294 11295 *cutoff = FALSE; 11296 11297 consdata = SCIPconsGetData(cons); 11298 assert(consdata != NULL); 11299 11300 nvars = consdata->nvars; 11301 11302 /* check whether the cliques have already been added */ 11303 if( consdata->cliquesadded || nvars == 0 ) 11304 return SCIP_OKAY; 11305 11306 /* make sure, the items are merged */ 11307 SCIP_CALL( mergeMultiples(scip, cons, cutoff) ); 11308 if( *cutoff ) 11309 return SCIP_OKAY; 11310 11311 /* make sure, the items are sorted by non-increasing weight */ 11312 sortItems(consdata); 11313 11314 assert(consdata->merged); 11315 11316 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons)); 11317 assert(conshdlrdata != NULL); 11318 11319 /* calculate a clique partition */ 11320 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) ); 11321 nnegcliques = consdata->nnegcliques; 11322 assert(nnegcliques <= nvars); 11323 11324 /* get temporary memory */ 11325 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) ); 11326 SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) ); 11327 BMSclearMemoryArray(gainweights, nvars); 11328 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) ); 11329 BMSclearMemoryArray(secondmaxweights, nnegcliques); 11330 11331 minactduetonegcliques = 0; 11332 11333 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */ 11334 if( nnegcliques < nvars ) 11335 { 11336 nnegcliques = 0; 11337 11338 for( i = 0; i < nvars; ++i ) 11339 { 11340 SCIP_Longint weight; 11341 11342 cliquenum = consdata->negcliquepartition[i]; 11343 assert(0 <= cliquenum && cliquenum <= nnegcliques); 11344 11345 weight = consdata->weights[i]; 11346 assert(weight > 0); 11347 11348 if( cliquenum == nnegcliques ) 11349 nnegcliques++; 11350 else 11351 { 11352 minactduetonegcliques += weight; 11353 if( secondmaxweights[cliquenum] == 0 ) 11354 secondmaxweights[cliquenum] = weight; 11355 } 11356 } 11357 } 11358 11359 /* add cliques, using negated cliques information */ 11360 if( minactduetonegcliques > 0 ) 11361 { 11362 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */ 11363 freecapacity = consdata->capacity - minactduetonegcliques; 11364 11365 SCIPdebugPrintCons(scip, cons, NULL); 11366 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", 11367 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity); 11368 11369 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */ 11370 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) ); 11371 11372 if( *cutoff ) 11373 goto TERMINATE; 11374 11375 nposcliquevars = 0; 11376 11377 for( i = nvars - 1; i >= 0; --i ) 11378 { 11379 /* if we would take the biggest weight instead of the second biggest */ 11380 cliquenum = consdata->negcliquepartition[i]; 11381 if( consdata->weights[i] > secondmaxweights[cliquenum] ) 11382 { 11383 poscliquevars[nposcliquevars] = consdata->vars[i]; 11384 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum]; 11385 ++nposcliquevars; 11386 } 11387 } 11388 11389 /* use the gain weights and free capacity to derive greedily cliques */ 11390 if( nposcliquevars > 1 ) 11391 { 11392 SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) ); 11393 11394 if( *cutoff ) 11395 goto TERMINATE; 11396 } 11397 } 11398 11399 /* build cliques by using the items with the maximal weights */ 11400 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) ); 11401 11402 TERMINATE: 11403 /* free temporary memory and mark the constraint */ 11404 SCIPfreeBufferArray(scip, &secondmaxweights); 11405 SCIPfreeBufferArray(scip, &gainweights); 11406 SCIPfreeBufferArray(scip, &poscliquevars); 11407 consdata->cliquesadded = TRUE; 11408 11409 return SCIP_OKAY; 11410 } 11411 11412 11413 /** gets the key of the given element */ 11414 static 11415 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons) 11416 { /*lint --e{715}*/ 11417 /* the key is the element itself */ 11418 return elem; 11419 } 11420 11421 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the 11422 * same coefficients 11423 */ 11424 static 11425 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons) 11426 { 11427 #ifndef NDEBUG 11428 SCIP* scip; 11429 #endif 11430 SCIP_CONSDATA* consdata1; 11431 SCIP_CONSDATA* consdata2; 11432 int i; 11433 11434 consdata1 = SCIPconsGetData((SCIP_CONS*)key1); 11435 consdata2 = SCIPconsGetData((SCIP_CONS*)key2); 11436 assert(consdata1->sorted); 11437 assert(consdata2->sorted); 11438 #ifndef NDEBUG 11439 scip = (SCIP*)userptr; 11440 assert(scip != NULL); 11441 #endif 11442 11443 /* checks trivial case */ 11444 if( consdata1->nvars != consdata2->nvars ) 11445 return FALSE; 11446 11447 for( i = consdata1->nvars - 1; i >= 0; --i ) 11448 { 11449 /* tests if variables are equal */ 11450 if( consdata1->vars[i] != consdata2->vars[i] ) 11451 { 11452 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 || 11453 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1); 11454 return FALSE; 11455 } 11456 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0); 11457 11458 /* tests if weights are equal too */ 11459 if( consdata1->weights[i] != consdata2->weights[i] ) 11460 return FALSE; 11461 } 11462 11463 return TRUE; 11464 } 11465 11466 /** returns the hash value of the key */ 11467 static 11468 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons) 11469 { 11470 #ifndef NDEBUG 11471 SCIP* scip; 11472 #endif 11473 SCIP_CONSDATA* consdata; 11474 uint64_t firstweight; 11475 int minidx; 11476 int mididx; 11477 int maxidx; 11478 11479 consdata = SCIPconsGetData((SCIP_CONS*)key); 11480 assert(consdata != NULL); 11481 assert(consdata->nvars > 0); 11482 11483 #ifndef NDEBUG 11484 scip = (SCIP*)userptr; 11485 assert(scip != NULL); 11486 #endif 11487 11488 /* sorts the constraints */ 11489 sortItems(consdata); 11490 11491 minidx = SCIPvarGetIndex(consdata->vars[0]); 11492 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]); 11493 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]); 11494 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0); 11495 11496 /* hash value depends on vectors of variable indices */ 11497 firstweight = (uint64_t)consdata->weights[0]; 11498 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight); 11499 } 11500 11501 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint 11502 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table 11503 */ 11504 static 11505 SCIP_RETCODE detectRedundantConstraints( 11506 SCIP* scip, /**< SCIP data structure */ 11507 BMS_BLKMEM* blkmem, /**< block memory */ 11508 SCIP_CONS** conss, /**< constraint set */ 11509 int nconss, /**< number of constraints in constraint set */ 11510 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */ 11511 int* ndelconss /**< pointer to count number of deleted constraints */ 11512 ) 11513 { 11514 SCIP_HASHTABLE* hashtable; 11515 int hashtablesize; 11516 int c; 11517 11518 assert(scip != NULL); 11519 assert(blkmem != NULL); 11520 assert(conss != NULL); 11521 assert(ndelconss != NULL); 11522 11523 /* create a hash table for the constraint set */ 11524 hashtablesize = nconss; 11525 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS); 11526 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize, 11527 hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) ); 11528 11529 /* check all constraints in the given set for redundancy */ 11530 for( c = nconss - 1; c >= 0; --c ) 11531 { 11532 SCIP_CONS* cons0; 11533 SCIP_CONS* cons1; 11534 SCIP_CONSDATA* consdata0; 11535 11536 cons0 = conss[c]; 11537 11538 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) ) 11539 continue; 11540 11541 consdata0 = SCIPconsGetData(cons0); 11542 assert(consdata0 != NULL); 11543 if( consdata0->nvars == 0 ) 11544 { 11545 if( consdata0->capacity < 0 ) 11546 { 11547 *cutoff = TRUE; 11548 goto TERMINATE; 11549 } 11550 else 11551 { 11552 SCIP_CALL( SCIPdelCons(scip, cons0) ); 11553 ++(*ndelconss); 11554 continue; 11555 } 11556 } 11557 11558 /* get constraint from current hash table with same variables and same weights as cons0 */ 11559 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0)); 11560 11561 if( cons1 != NULL ) 11562 { 11563 SCIP_CONS* consstay; 11564 SCIP_CONS* consdel; 11565 SCIP_CONSDATA* consdata1; 11566 11567 assert(SCIPconsIsActive(cons1)); 11568 assert(!SCIPconsIsModifiable(cons1)); 11569 11570 /* constraint found: create a new constraint with same coefficients and best left and right hand side; 11571 * delete old constraints afterwards 11572 */ 11573 consdata1 = SCIPconsGetData(cons1); 11574 11575 assert(consdata1 != NULL); 11576 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars); 11577 11578 assert(consdata0->sorted && consdata1->sorted); 11579 assert(consdata0->vars[0] == consdata1->vars[0]); 11580 assert(consdata0->weights[0] == consdata1->weights[0]); 11581 11582 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n", 11583 SCIPconsGetName(cons0), SCIPconsGetName(cons1)); 11584 11585 /* check which constraint has to stay; */ 11586 if( consdata0->capacity < consdata1->capacity ) 11587 { 11588 consstay = cons0; 11589 consdel = cons1; 11590 11591 /* exchange consdel with consstay in hashtable */ 11592 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) ); 11593 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) ); 11594 } 11595 else 11596 { 11597 consstay = cons1; 11598 consdel = cons0; 11599 } 11600 11601 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */ 11602 SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) ); 11603 11604 /* delete consdel */ 11605 SCIP_CALL( SCIPdelCons(scip, consdel) ); 11606 ++(*ndelconss); 11607 11608 assert(SCIPconsIsActive(consstay)); 11609 } 11610 else 11611 { 11612 /* no such constraint in current hash table: insert cons0 into hash table */ 11613 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) ); 11614 } 11615 } 11616 11617 TERMINATE: 11618 /* free hash table */ 11619 SCIPhashtableFree(&hashtable); 11620 11621 return SCIP_OKAY; 11622 } 11623 11624 11625 /** compares constraint with all prior constraints for possible redundancy or aggregation, 11626 * and removes or changes constraint accordingly 11627 */ 11628 static 11629 SCIP_RETCODE preprocessConstraintPairs( 11630 SCIP* scip, /**< SCIP data structure */ 11631 SCIP_CONS** conss, /**< constraint set */ 11632 int firstchange, /**< first constraint that changed since last pair preprocessing round */ 11633 int chkind, /**< index of constraint to check against all prior indices upto startind */ 11634 int* ndelconss /**< pointer to count number of deleted constraints */ 11635 ) 11636 { 11637 SCIP_CONS* cons0; 11638 SCIP_CONSDATA* consdata0; 11639 int c; 11640 11641 assert(scip != NULL); 11642 assert(conss != NULL); 11643 assert(firstchange <= chkind); 11644 assert(ndelconss != NULL); 11645 11646 /* get the constraint to be checked against all prior constraints */ 11647 cons0 = conss[chkind]; 11648 assert(cons0 != NULL); 11649 assert(SCIPconsIsActive(cons0)); 11650 assert(!SCIPconsIsModifiable(cons0)); 11651 11652 consdata0 = SCIPconsGetData(cons0); 11653 assert(consdata0 != NULL); 11654 assert(consdata0->nvars >= 1); 11655 assert(consdata0->merged); 11656 11657 /* sort the constraint */ 11658 sortItems(consdata0); 11659 11660 /* see #2970 */ 11661 if( consdata0->capacity == 0 ) 11662 return SCIP_OKAY; 11663 11664 /* check constraint against all prior constraints */ 11665 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c ) 11666 { 11667 SCIP_CONS* cons1; 11668 SCIP_CONSDATA* consdata1; 11669 SCIP_Bool iscons0incons1contained; 11670 SCIP_Bool iscons1incons0contained; 11671 SCIP_Real quotient; 11672 int v; 11673 int v0; 11674 int v1; 11675 11676 cons1 = conss[c]; 11677 assert(cons1 != NULL); 11678 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) ) 11679 continue; 11680 11681 consdata1 = SCIPconsGetData(cons1); 11682 assert(consdata1 != NULL); 11683 11684 /* if both constraints didn't change since last pair processing, we can ignore the pair */ 11685 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/ 11686 continue; 11687 11688 assert(consdata1->nvars >= 1); 11689 assert(consdata1->merged); 11690 11691 /* sort the constraint */ 11692 sortItems(consdata1); 11693 11694 /* see #2970 */ 11695 if( consdata1->capacity == 0 ) 11696 continue; 11697 11698 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity); 11699 11700 if( consdata0->nvars > consdata1->nvars ) 11701 { 11702 iscons0incons1contained = FALSE; 11703 iscons1incons0contained = TRUE; 11704 v = consdata1->nvars - 1; 11705 } 11706 else if( consdata0->nvars < consdata1->nvars ) 11707 { 11708 iscons0incons1contained = TRUE; 11709 iscons1incons0contained = FALSE; 11710 v = consdata0->nvars - 1; 11711 } 11712 else 11713 { 11714 iscons0incons1contained = TRUE; 11715 iscons1incons0contained = TRUE; 11716 v = consdata0->nvars - 1; 11717 } 11718 11719 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1)); 11720 11721 /* check consdata0 against consdata1: 11722 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables 11723 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant 11724 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables 11725 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant 11726 */ 11727 v0 = consdata0->nvars - 1; 11728 v1 = consdata1->nvars - 1; 11729 11730 while( v >= 0 ) 11731 { 11732 assert(iscons0incons1contained || iscons1incons0contained); 11733 11734 /* now there are more variables in cons1 left */ 11735 if( v1 > v0 ) 11736 { 11737 iscons1incons0contained = FALSE; 11738 if( !iscons0incons1contained ) 11739 break; 11740 } 11741 /* now there are more variables in cons0 left */ 11742 else if( v1 < v0 ) 11743 { 11744 iscons0incons1contained = FALSE; 11745 if( !iscons1incons0contained ) 11746 break; 11747 } 11748 11749 assert(v == v0 || v == v1); 11750 assert(v0 >= 0); 11751 assert(v1 >= 0); 11752 11753 /* both variables are the same */ 11754 if( consdata0->vars[v0] == consdata1->vars[v1] ) 11755 { 11756 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */ 11757 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) ) 11758 { 11759 iscons1incons0contained = FALSE; 11760 if( !iscons0incons1contained ) 11761 break; 11762 } 11763 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */ 11764 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) ) 11765 { 11766 iscons0incons1contained = FALSE; 11767 if( !iscons1incons0contained ) 11768 break; 11769 } 11770 --v0; 11771 --v1; 11772 --v; 11773 } 11774 else 11775 { 11776 /* both constraints have a variables which is not part of the other constraint, so stop */ 11777 if( iscons0incons1contained && iscons1incons0contained ) 11778 { 11779 iscons0incons1contained = FALSE; 11780 iscons1incons0contained = FALSE; 11781 break; 11782 } 11783 assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained); 11784 assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained); 11785 /* continue to the next variable */ 11786 if( iscons0incons1contained ) 11787 --v1; 11788 else 11789 --v0; 11790 } 11791 } 11792 /* neither one constraint was contained in another or we checked all variables of one constraint against the 11793 * other 11794 */ 11795 assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1); 11796 11797 if( iscons1incons0contained ) 11798 { 11799 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1)); 11800 SCIPdebugPrintCons(scip, cons1, NULL); 11801 11802 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */ 11803 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) ); 11804 11805 SCIP_CALL( SCIPdelCons(scip, cons1) ); 11806 ++(*ndelconss); 11807 } 11808 else if( iscons0incons1contained ) 11809 { 11810 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0)); 11811 SCIPdebugPrintCons(scip, cons0, NULL); 11812 11813 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */ 11814 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) ); 11815 11816 SCIP_CALL( SCIPdelCons(scip, cons0) ); 11817 ++(*ndelconss); 11818 break; 11819 } 11820 } 11821 11822 return SCIP_OKAY; 11823 } 11824 11825 /** helper function to enforce constraints */ 11826 static 11827 SCIP_RETCODE enforceConstraint( 11828 SCIP* scip, /**< SCIP data structure */ 11829 SCIP_CONSHDLR* conshdlr, /**< constraint handler */ 11830 SCIP_CONS** conss, /**< constraints to process */ 11831 int nconss, /**< number of constraints */ 11832 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */ 11833 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */ 11834 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */ 11835 ) 11836 { 11837 SCIP_CONSHDLRDATA* conshdlrdata; 11838 SCIP_Bool violated; 11839 SCIP_Bool cutoff = FALSE; 11840 int maxncuts; 11841 int ncuts = 0; 11842 int i; 11843 11844 *result = SCIP_FEASIBLE; 11845 11846 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss, 11847 sol == NULL ? "LP" : "relaxation"); 11848 11849 /* get maximal number of cuts per round */ 11850 conshdlrdata = SCIPconshdlrGetData(conshdlr); 11851 assert(conshdlrdata != NULL); 11852 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts); 11853 11854 /* search for violated useful knapsack constraints */ 11855 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ ) 11856 { 11857 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) ); 11858 if( violated ) 11859 { 11860 /* add knapsack constraint as LP row to the relaxation */ 11861 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) ); 11862 ncuts++; 11863 } 11864 } 11865 11866 /* as long as no violations were found, search for violated obsolete knapsack constraints */ 11867 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ ) 11868 { 11869 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) ); 11870 if( violated ) 11871 { 11872 /* add knapsack constraint as LP row to the relaxation */ 11873 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) ); 11874 ncuts++; 11875 } 11876 } 11877 11878 /* adjust the result code */ 11879 if ( cutoff ) 11880 *result = SCIP_CUTOFF; 11881 else if ( ncuts > 0 ) 11882 *result = SCIP_SEPARATED; 11883 11884 return SCIP_OKAY; 11885 } 11886 11887 /* 11888 * Linear constraint upgrading 11889 */ 11890 11891 /** creates and captures a knapsack constraint out of a linear inequality */ 11892 static 11893 SCIP_RETCODE createNormalizedKnapsack( 11894 SCIP* scip, /**< SCIP data structure */ 11895 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 11896 const char* name, /**< name of constraint */ 11897 int nvars, /**< number of variables in the constraint */ 11898 SCIP_VAR** vars, /**< array with variables of constraint entries */ 11899 SCIP_Real* vals, /**< array with inequality coefficients */ 11900 SCIP_Real lhs, /**< left hand side of inequality */ 11901 SCIP_Real rhs, /**< right hand side of inequality */ 11902 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? 11903 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ 11904 SCIP_Bool separate, /**< should the constraint be separated during LP processing? 11905 * Usually set to TRUE. */ 11906 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? 11907 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 11908 SCIP_Bool check, /**< should the constraint be checked for feasibility? 11909 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 11910 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? 11911 * Usually set to TRUE. */ 11912 SCIP_Bool local, /**< is constraint only valid locally? 11913 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ 11914 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? 11915 * Usually set to FALSE. In column generation applications, set to TRUE if pricing 11916 * adds coefficients to this constraint. */ 11917 SCIP_Bool dynamic, /**< is constraint subject to aging? 11918 * Usually set to FALSE. Set to TRUE for own cuts which 11919 * are separated as constraints. */ 11920 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? 11921 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ 11922 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even 11923 * if it may be moved to a more global node? 11924 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ 11925 ) 11926 { 11927 SCIP_VAR** transvars; 11928 SCIP_Longint* weights; 11929 SCIP_Longint capacity; 11930 SCIP_Longint weight; 11931 int mult; 11932 int v; 11933 11934 assert(nvars == 0 || vars != NULL); 11935 assert(nvars == 0 || vals != NULL); 11936 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs)); 11937 11938 /* get temporary memory */ 11939 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) ); 11940 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) ); 11941 11942 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient; 11943 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1 11944 */ 11945 if( SCIPisInfinity(scip, rhs) ) 11946 { 11947 mult = -1; 11948 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs); 11949 } 11950 else 11951 { 11952 mult = +1; 11953 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs); 11954 } 11955 11956 /* negate positive or negative variables */ 11957 for( v = 0; v < nvars; ++v ) 11958 { 11959 assert(SCIPisFeasIntegral(scip, vals[v])); 11960 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]); 11961 if( weight > 0 ) 11962 { 11963 transvars[v] = vars[v]; 11964 weights[v] = weight; 11965 } 11966 else 11967 { 11968 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) ); 11969 weights[v] = -weight; /*lint !e2704*/ 11970 capacity -= weight; 11971 } 11972 assert(transvars[v] != NULL); 11973 } 11974 11975 /* create the constraint */ 11976 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity, 11977 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) ); 11978 11979 /* free temporary memory */ 11980 SCIPfreeBufferArray(scip, &weights); 11981 SCIPfreeBufferArray(scip, &transvars); 11982 11983 return SCIP_OKAY; 11984 } 11985 11986 /** tries to upgrade a linear constraint into a knapsack constraint */ 11987 static 11988 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack) 11989 { /*lint --e{715}*/ 11990 SCIP_Bool upgrade; 11991 11992 assert(upgdcons != NULL); 11993 11994 /* check, if linear constraint can be upgraded to a knapsack constraint 11995 * - all variables must be binary 11996 * - all coefficients must be integral 11997 * - exactly one of the sides must be infinite 11998 * note that this includes the case of negative capacity, which has been 11999 * observed to occur, e.g., when upgrading a conflict constraint 12000 */ 12001 upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars) 12002 && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars) 12003 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs)); 12004 12005 if( upgrade ) 12006 { 12007 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons)); 12008 12009 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */ 12010 assert(!SCIPconsIsModifiable(cons)); 12011 SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs, 12012 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 12013 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), 12014 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), 12015 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 12016 } 12017 12018 return SCIP_OKAY; 12019 } 12020 12021 /** adds symmetry information of constraint to a symmetry detection graph */ 12022 static 12023 SCIP_RETCODE addSymmetryInformation( 12024 SCIP* scip, /**< SCIP pointer */ 12025 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */ 12026 SCIP_CONS* cons, /**< constraint */ 12027 SYM_GRAPH* graph, /**< symmetry detection graph */ 12028 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */ 12029 ) 12030 { 12031 SCIP_CONSDATA* consdata; 12032 SCIP_VAR** vars; 12033 SCIP_Real* vals; 12034 SCIP_Real constant = 0.0; 12035 SCIP_Real rhs; 12036 int nlocvars; 12037 int nvars; 12038 int i; 12039 12040 assert(scip != NULL); 12041 assert(cons != NULL); 12042 assert(graph != NULL); 12043 assert(success != NULL); 12044 12045 consdata = SCIPconsGetData(cons); 12046 assert(consdata != NULL); 12047 assert(graph != NULL); 12048 12049 /* get active variables of the constraint */ 12050 nvars = SCIPgetNVars(scip); 12051 nlocvars = consdata->nvars; 12052 12053 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); 12054 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) ); 12055 12056 for( i = 0; i < consdata->nvars; ++i ) 12057 { 12058 vars[i] = consdata->vars[i]; 12059 vals[i] = (SCIP_Real) consdata->weights[i]; 12060 } 12061 12062 SCIP_CALL( SCIPgetActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) ); 12063 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant; 12064 12065 SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars, 12066 cons, -SCIPinfinity(scip), rhs, success) ); 12067 12068 SCIPfreeBufferArray(scip, &vals); 12069 SCIPfreeBufferArray(scip, &vars); 12070 12071 return SCIP_OKAY; 12072 } 12073 12074 /* 12075 * Callback methods of constraint handler 12076 */ 12077 12078 /** copy method for constraint handler plugins (called when SCIP copies plugins) */ 12079 /**! [SnippetConsCopyKnapsack] */ 12080 static 12081 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack) 12082 { /*lint --e{715}*/ 12083 assert(scip != NULL); 12084 assert(conshdlr != NULL); 12085 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 12086 12087 /* call inclusion method of constraint handler */ 12088 SCIP_CALL( SCIPincludeConshdlrKnapsack(scip) ); 12089 12090 *valid = TRUE; 12091 12092 return SCIP_OKAY; 12093 } 12094 /**! [SnippetConsCopyKnapsack] */ 12095 12096 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */ 12097 /**! [SnippetConsFreeKnapsack] */ 12098 static 12099 SCIP_DECL_CONSFREE(consFreeKnapsack) 12100 { /*lint --e{715}*/ 12101 SCIP_CONSHDLRDATA* conshdlrdata; 12102 12103 /* free constraint handler data */ 12104 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12105 assert(conshdlrdata != NULL); 12106 12107 SCIPfreeBlockMemory(scip, &conshdlrdata); 12108 12109 SCIPconshdlrSetData(conshdlr, NULL); 12110 12111 return SCIP_OKAY; 12112 } 12113 /**! [SnippetConsFreeKnapsack] */ 12114 12115 12116 /** initialization method of constraint handler (called after problem was transformed) */ 12117 static 12118 SCIP_DECL_CONSINIT(consInitKnapsack) 12119 { /*lint --e{715}*/ 12120 SCIP_CONSHDLRDATA* conshdlrdata; 12121 int nvars; 12122 12123 assert( scip != NULL ); 12124 assert( conshdlr != NULL ); 12125 12126 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12127 assert(conshdlrdata != NULL); 12128 12129 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */ 12130 nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip); 12131 12132 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) ); 12133 conshdlrdata->reals1size = nvars; 12134 12135 return SCIP_OKAY; 12136 } 12137 12138 /** deinitialization method of constraint handler (called before transformed problem is freed) */ 12139 static 12140 SCIP_DECL_CONSEXIT(consExitKnapsack) 12141 { /*lint --e{715}*/ 12142 SCIP_CONSHDLRDATA* conshdlrdata; 12143 12144 assert( scip != NULL ); 12145 assert( conshdlr != NULL ); 12146 12147 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12148 assert(conshdlrdata != NULL); 12149 12150 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size); 12151 conshdlrdata->reals1size = 0; 12152 12153 return SCIP_OKAY; 12154 } 12155 12156 12157 /** presolving initialization method of constraint handler (called when presolving is about to begin) */ 12158 static 12159 SCIP_DECL_CONSINITPRE(consInitpreKnapsack) 12160 { /*lint --e{715}*/ 12161 SCIP_CONSHDLRDATA* conshdlrdata; 12162 int nvars; 12163 12164 assert(scip != NULL); 12165 assert(conshdlr != NULL); 12166 assert(nconss == 0 || conss != NULL); 12167 12168 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12169 assert(conshdlrdata != NULL); 12170 12171 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */ 12172 nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip); 12173 12174 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) ); 12175 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) ); 12176 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) ); 12177 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) ); 12178 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) ); 12179 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) ); 12180 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) ); 12181 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) ); 12182 12183 conshdlrdata->ints1size = nvars; 12184 conshdlrdata->ints2size = nvars; 12185 conshdlrdata->longints1size = nvars; 12186 conshdlrdata->longints2size = nvars; 12187 conshdlrdata->bools1size = nvars; 12188 conshdlrdata->bools2size = nvars; 12189 conshdlrdata->bools3size = nvars; 12190 conshdlrdata->bools4size = nvars; 12191 12192 #ifdef WITH_CARDINALITY_UPGRADE 12193 conshdlrdata->upgradedcard = FALSE; 12194 #endif 12195 12196 return SCIP_OKAY; 12197 } 12198 12199 12200 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */ 12201 static 12202 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack) 12203 { /*lint --e{715}*/ 12204 SCIP_CONSHDLRDATA* conshdlrdata; 12205 int c; 12206 12207 assert(scip != NULL); 12208 assert(conshdlr != NULL); 12209 12210 for( c = 0; c < nconss; ++c ) 12211 { 12212 if( !SCIPconsIsDeleted(conss[c]) ) 12213 { 12214 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */ 12215 SCIP_CALL( applyFixings(scip, conss[c], NULL) ); 12216 } 12217 } 12218 12219 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12220 assert(conshdlrdata != NULL); 12221 12222 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size); 12223 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size); 12224 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size); 12225 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size); 12226 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size); 12227 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size); 12228 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size); 12229 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size); 12230 12231 conshdlrdata->ints1size = 0; 12232 conshdlrdata->ints2size = 0; 12233 conshdlrdata->longints1size = 0; 12234 conshdlrdata->longints2size = 0; 12235 conshdlrdata->bools1size = 0; 12236 conshdlrdata->bools2size = 0; 12237 conshdlrdata->bools3size = 0; 12238 conshdlrdata->bools4size = 0; 12239 12240 return SCIP_OKAY; 12241 } 12242 12243 /** solving process initialization method of constraint handler */ 12244 static 12245 SCIP_DECL_CONSINITSOL(consInitsolKnapsack) 12246 { /*lint --e{715}*/ 12247 /* add nlrow representation to NLP, if NLP had been constructed */ 12248 if( SCIPisNLPConstructed(scip) ) 12249 { 12250 int c; 12251 for( c = 0; c < nconss; ++c ) 12252 { 12253 SCIP_CALL( addNlrow(scip, conss[c]) ); 12254 } 12255 } 12256 12257 return SCIP_OKAY; 12258 } 12259 12260 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */ 12261 static 12262 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack) 12263 { /*lint --e{715}*/ 12264 SCIP_CONSDATA* consdata; 12265 int c; 12266 12267 assert( scip != NULL ); 12268 12269 /* release the rows and nlrows of all constraints */ 12270 for( c = 0; c < nconss; ++c ) 12271 { 12272 consdata = SCIPconsGetData(conss[c]); 12273 assert(consdata != NULL); 12274 12275 if( consdata->row != NULL ) 12276 { 12277 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) ); 12278 } 12279 12280 if( consdata->nlrow != NULL ) 12281 { 12282 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) ); 12283 } 12284 } 12285 12286 return SCIP_OKAY; 12287 } 12288 12289 /** frees specific constraint data */ 12290 static 12291 SCIP_DECL_CONSDELETE(consDeleteKnapsack) 12292 { /*lint --e{715}*/ 12293 SCIP_CONSHDLRDATA* conshdlrdata; 12294 12295 assert(conshdlr != NULL); 12296 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 12297 12298 /* get event handler */ 12299 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12300 assert(conshdlrdata != NULL); 12301 assert(conshdlrdata->eventhdlr != NULL); 12302 12303 /* free knapsack constraint */ 12304 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) ); 12305 12306 return SCIP_OKAY; 12307 } 12308 12309 /** transforms constraint data into data belonging to the transformed problem */ 12310 /**! [SnippetConsTransKnapsack]*/ 12311 static 12312 SCIP_DECL_CONSTRANS(consTransKnapsack) 12313 { /*lint --e{715}*/ 12314 SCIP_CONSHDLRDATA* conshdlrdata; 12315 SCIP_CONSDATA* sourcedata; 12316 SCIP_CONSDATA* targetdata; 12317 12318 assert(conshdlr != NULL); 12319 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); 12320 assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING); 12321 assert(sourcecons != NULL); 12322 assert(targetcons != NULL); 12323 12324 sourcedata = SCIPconsGetData(sourcecons); 12325 assert(sourcedata != NULL); 12326 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */ 12327 12328 /* get event handler */ 12329 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12330 assert(conshdlrdata != NULL); 12331 assert(conshdlrdata->eventhdlr != NULL); 12332 12333 /* create target constraint data */ 12334 SCIP_CALL( consdataCreate(scip, &targetdata, 12335 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) ); 12336 12337 /* create target constraint */ 12338 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata, 12339 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons), 12340 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), 12341 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons), 12342 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) ); 12343 12344 /* catch events for variables */ 12345 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) ); 12346 12347 return SCIP_OKAY; 12348 } 12349 /**! [SnippetConsTransKnapsack]*/ 12350 12351 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */ 12352 static 12353 SCIP_DECL_CONSINITLP(consInitlpKnapsack) 12354 { /*lint --e{715}*/ 12355 int i; 12356 12357 *infeasible = FALSE; 12358 12359 for( i = 0; i < nconss && !(*infeasible); i++ ) 12360 { 12361 assert(SCIPconsIsInitial(conss[i])); 12362 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) ); 12363 } 12364 12365 return SCIP_OKAY; 12366 } 12367 12368 /** separation method of constraint handler for LP solutions */ 12369 static 12370 SCIP_DECL_CONSSEPALP(consSepalpKnapsack) 12371 { /*lint --e{715}*/ 12372 SCIP_CONSHDLRDATA* conshdlrdata; 12373 SCIP_Bool sepacardinality; 12374 SCIP_Bool cutoff; 12375 12376 SCIP_Real loclowerbound; 12377 SCIP_Real glblowerbound; 12378 SCIP_Real cutoffbound; 12379 SCIP_Real maxbound; 12380 12381 int depth; 12382 int nrounds; 12383 int sepafreq; 12384 int sepacardfreq; 12385 int ncuts; 12386 int maxsepacuts; 12387 int i; 12388 12389 *result = SCIP_DIDNOTRUN; 12390 12391 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12392 assert(conshdlrdata != NULL); 12393 12394 depth = SCIPgetDepth(scip); 12395 nrounds = SCIPgetNSepaRounds(scip); 12396 12397 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n", 12398 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds); 12399 12400 /* only call the separator a given number of times at each node */ 12401 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot) 12402 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) ) 12403 return SCIP_OKAY; 12404 12405 /* check, if we should additionally separate knapsack cuts */ 12406 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr); 12407 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq; 12408 sepacardinality = (conshdlrdata->sepacardfreq >= 0) 12409 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0))); 12410 12411 /* check dual bound to see if we want to produce knapsack cuts at this node */ 12412 loclowerbound = SCIPgetLocalLowerbound(scip); 12413 glblowerbound = SCIPgetLowerbound(scip); 12414 cutoffbound = SCIPgetCutoffbound(scip); 12415 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound); 12416 sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound); 12417 sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0); 12418 12419 /* get the maximal number of cuts allowed in a separation round */ 12420 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts); 12421 12422 *result = SCIP_DIDNOTFIND; 12423 ncuts = 0; 12424 cutoff = FALSE; 12425 12426 /* separate useful constraints */ 12427 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ ) 12428 { 12429 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) ); 12430 } 12431 12432 /* adjust return value */ 12433 if ( cutoff ) 12434 *result = SCIP_CUTOFF; 12435 else if ( ncuts > 0 ) 12436 *result = SCIP_SEPARATED; 12437 12438 return SCIP_OKAY; 12439 } 12440 12441 12442 /** separation method of constraint handler for arbitrary primal solutions */ 12443 static 12444 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack) 12445 { /*lint --e{715}*/ 12446 SCIP_CONSHDLRDATA* conshdlrdata; 12447 SCIP_Bool sepacardinality; 12448 SCIP_Bool cutoff; 12449 12450 int depth; 12451 int nrounds; 12452 int sepafreq; 12453 int sepacardfreq; 12454 int ncuts; 12455 int maxsepacuts; 12456 int i; 12457 12458 *result = SCIP_DIDNOTRUN; 12459 12460 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12461 assert(conshdlrdata != NULL); 12462 12463 depth = SCIPgetDepth(scip); 12464 nrounds = SCIPgetNSepaRounds(scip); 12465 12466 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n", 12467 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds); 12468 12469 /* only call the separator a given number of times at each node */ 12470 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot) 12471 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) ) 12472 return SCIP_OKAY; 12473 12474 /* check, if we should additionally separate knapsack cuts */ 12475 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr); 12476 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq; 12477 sepacardinality = (conshdlrdata->sepacardfreq >= 0) 12478 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0))); 12479 12480 /* get the maximal number of cuts allowed in a separation round */ 12481 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts); 12482 12483 *result = SCIP_DIDNOTFIND; 12484 ncuts = 0; 12485 cutoff = FALSE; 12486 12487 /* separate useful constraints */ 12488 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ ) 12489 { 12490 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) ); 12491 } 12492 12493 /* adjust return value */ 12494 if ( cutoff ) 12495 *result = SCIP_CUTOFF; 12496 else if( ncuts > 0 ) 12497 *result = SCIP_SEPARATED; 12498 12499 return SCIP_OKAY; 12500 } 12501 12502 /** constraint enforcing method of constraint handler for LP solutions */ 12503 static 12504 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack) 12505 { /*lint --e{715}*/ 12506 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) ); 12507 12508 return SCIP_OKAY; 12509 } 12510 12511 /** constraint enforcing method of constraint handler for relaxation solutions */ 12512 static 12513 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack) 12514 { /*lint --e{715}*/ 12515 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) ); 12516 12517 return SCIP_OKAY; 12518 } 12519 12520 /** constraint enforcing method of constraint handler for pseudo solutions */ 12521 static 12522 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack) 12523 { /*lint --e{715}*/ 12524 SCIP_Bool violated; 12525 int i; 12526 12527 for( i = 0; i < nconss; i++ ) 12528 { 12529 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) ); 12530 if( violated ) 12531 { 12532 *result = SCIP_INFEASIBLE; 12533 return SCIP_OKAY; 12534 } 12535 } 12536 *result = SCIP_FEASIBLE; 12537 12538 return SCIP_OKAY; 12539 } 12540 12541 /** feasibility check method of constraint handler for integral solutions */ 12542 static 12543 SCIP_DECL_CONSCHECK(consCheckKnapsack) 12544 { /*lint --e{715}*/ 12545 SCIP_Bool violated; 12546 int i; 12547 12548 *result = SCIP_FEASIBLE; 12549 12550 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ ) 12551 { 12552 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) ); 12553 if( violated ) 12554 *result = SCIP_INFEASIBLE; 12555 } 12556 12557 return SCIP_OKAY; 12558 } 12559 12560 /** domain propagation method of constraint handler */ 12561 static 12562 SCIP_DECL_CONSPROP(consPropKnapsack) 12563 { /*lint --e{715}*/ 12564 SCIP_CONSHDLRDATA* conshdlrdata; 12565 SCIP_Bool cutoff; 12566 SCIP_Bool redundant; 12567 SCIP_Bool inpresolve; 12568 int nfixedvars; 12569 int i; 12570 12571 cutoff = FALSE; 12572 nfixedvars = 0; 12573 12574 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12575 assert(conshdlrdata != NULL); 12576 12577 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE); 12578 assert(!inpresolve || SCIPinProbing(scip)); 12579 12580 /* process useful constraints */ 12581 for( i = 0; i < nmarkedconss && !cutoff; i++ ) 12582 { 12583 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode, 12584 * otherwise the multi-aggregation should be resolved 12585 */ 12586 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr ) 12587 continue; 12588 #ifndef NDEBUG 12589 else 12590 assert(!(SCIPconsGetData(conss[i])->existmultaggr)); 12591 #endif 12592 12593 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) ); 12594 12595 /* unmark the constraint to be propagated */ 12596 SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) ); 12597 } 12598 12599 /* adjust result code */ 12600 if( cutoff ) 12601 *result = SCIP_CUTOFF; 12602 else if( nfixedvars > 0 ) 12603 *result = SCIP_REDUCEDDOM; 12604 else 12605 *result = SCIP_DIDNOTFIND; 12606 12607 return SCIP_OKAY; /*lint !e438*/ 12608 } 12609 12610 /** presolving method of constraint handler */ 12611 static 12612 SCIP_DECL_CONSPRESOL(consPresolKnapsack) 12613 { /*lint --e{574,715}*/ 12614 SCIP_CONSHDLRDATA* conshdlrdata; 12615 SCIP_CONSDATA* consdata; 12616 SCIP_CONS* cons; 12617 SCIP_Bool cutoff; 12618 SCIP_Bool redundant; 12619 SCIP_Bool success; 12620 int oldnfixedvars; 12621 int oldnchgbds; 12622 int oldndelconss; 12623 int oldnaddconss; 12624 int oldnchgcoefs; 12625 int oldnchgsides; 12626 int firstchange; 12627 int c; 12628 SCIP_Bool newchanges; 12629 12630 /* remember old preprocessing counters */ 12631 cutoff = FALSE; 12632 oldnfixedvars = *nfixedvars; 12633 oldnchgbds = *nchgbds; 12634 oldndelconss = *ndelconss; 12635 oldnaddconss = *naddconss; 12636 oldnchgcoefs = *nchgcoefs; 12637 oldnchgsides = *nchgsides; 12638 firstchange = INT_MAX; 12639 12640 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0); 12641 12642 conshdlrdata = SCIPconshdlrGetData(conshdlr); 12643 assert(conshdlrdata != NULL); 12644 12645 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ ) 12646 { 12647 int thisnfixedvars; 12648 int thisnchgbds; 12649 12650 cons = conss[c]; 12651 consdata = SCIPconsGetData(cons); 12652 assert(consdata != NULL); 12653 12654 /* update data structures */ 12655 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */ 12656 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds ) 12657 { 12658 SCIP_CALL( applyFixings(scip, cons, &cutoff) ); 12659 if( cutoff ) 12660 break; 12661 } 12662 12663 /* force presolving the constraint in the initial round */ 12664 if( nrounds == 0 ) 12665 consdata->presolvedtiming = 0; 12666 else if( consdata->presolvedtiming >= presoltiming ) 12667 continue; 12668 12669 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons)); 12670 SCIPdebugPrintCons(scip, cons, NULL); 12671 consdata->presolvedtiming = presoltiming; 12672 12673 thisnfixedvars = *nfixedvars; 12674 thisnchgbds = *nchgbds; 12675 12676 /* merge constraint, so propagation works better */ 12677 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) ); 12678 if( cutoff ) 12679 break; 12680 12681 /* add cliques in the knapsack to the clique table */ 12682 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 ) 12683 { 12684 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) ); 12685 if( cutoff ) 12686 break; 12687 } 12688 12689 /* propagate constraint */ 12690 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE ) 12691 { 12692 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) ); 12693 12694 if( cutoff ) 12695 break; 12696 if( redundant ) 12697 { 12698 (*ndelconss)++; 12699 continue; 12700 } 12701 } 12702 12703 /* remove again all fixed variables, if further fixings were found */ 12704 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds ) 12705 { 12706 SCIP_CALL( applyFixings(scip, cons, &cutoff) ); 12707 if( cutoff ) 12708 break; 12709 12710 thisnfixedvars = *nfixedvars; 12711 } 12712 12713 if( !SCIPconsIsModifiable(cons) ) 12714 { 12715 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */ 12716 if( consdata->weightsum <= consdata->capacity ) 12717 { 12718 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n", 12719 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity); 12720 SCIP_CALL( SCIPdelConsLocal(scip, cons) ); 12721 continue; 12722 } 12723 12724 /* divide weights by their greatest common divisor */ 12725 normalizeWeights(cons, nchgcoefs, nchgsides); 12726 12727 /* try to simplify inequalities */ 12728 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 ) 12729 { 12730 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) ); 12731 if( cutoff ) 12732 break; 12733 12734 if( SCIPconsIsDeleted(cons) ) 12735 continue; 12736 12737 /* remove again all fixed variables, if further fixings were found */ 12738 if( *nfixedvars > thisnfixedvars ) 12739 { 12740 SCIP_CALL(applyFixings(scip, cons, &cutoff)); 12741 if( cutoff ) 12742 break; 12743 } 12744 } 12745 12746 /* tighten capacity and weights */ 12747 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) ); 12748 if( cutoff ) 12749 break; 12750 12751 if( SCIPconsIsActive(cons) ) 12752 { 12753 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 ) 12754 { 12755 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the 12756 * dual reduction 12757 */ 12758 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) ); 12759 if( redundant ) 12760 continue; 12761 } 12762 12763 /* check if knapsack constraint is parallel to objective function */ 12764 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) ); 12765 } 12766 } 12767 /* remember the first changed constraint to begin the next aggregation round with */ 12768 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE ) 12769 firstchange = c; 12770 } 12771 12772 /* preprocess pairs of knapsack constraints */ 12773 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 ) 12774 { 12775 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */ 12776 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) ); 12777 } 12778 12779 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) ) 12780 success = TRUE; 12781 else 12782 success = FALSE; 12783 12784 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 ) 12785 { 12786 SCIP_Longint npaircomparisons; 12787 12788 npaircomparisons = 0; 12789 oldndelconss = *ndelconss; 12790 oldnchgsides = *nchgsides; 12791 oldnchgcoefs = *nchgcoefs; 12792 12793 for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c ) 12794 { 12795 cons = conss[c]; 12796 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) ) 12797 continue; 12798 12799 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange)); 12800 12801 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) ); 12802 12803 if( npaircomparisons > NMINCOMPARISONS ) 12804 { 12805 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) ) 12806 success = TRUE; 12807 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 + 12808 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS ) 12809 break; 12810 oldndelconss = *ndelconss; 12811 oldnchgsides = *nchgsides; 12812 oldnchgcoefs = *nchgcoefs; 12813 npaircomparisons = 0; 12814 } 12815 } 12816 } 12817 #ifdef WITH_CARDINALITY_UPGRADE 12818 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack 12819 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous 12820 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with 12821 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary 12822 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem 12823 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0 12824 * as well, we better keep this code disabled. */ 12825 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */ 12826 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard ) 12827 { 12828 SCIP_HASHMAP* varhash; 12829 SCIP_VAR** cardvars; 12830 SCIP_Real* cardweights; 12831 int noldupgdconss; 12832 int nscipvars; 12833 int makeupgrade; 12834 12835 noldupgdconss = *nupgdconss; 12836 nscipvars = SCIPgetNVars(scip); 12837 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) ); 12838 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) ); 12839 12840 /* set up hash map */ 12841 SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) ); 12842 12843 /* We loop through all cardinality constraints twice: 12844 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a 12845 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up 12846 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update. 12847 * - Second, upgrade knapsack constraints to cardinality constraints. */ 12848 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade) 12849 { 12850 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c) 12851 { 12852 SCIP_CONS* cardcons; 12853 SCIP_VAR** vars; 12854 SCIP_Longint* weights; 12855 int nvars; 12856 int v; 12857 12858 cons = conss[c]; 12859 assert( cons != NULL ); 12860 consdata = SCIPconsGetData(cons); 12861 assert( consdata != NULL ); 12862 12863 nvars = consdata->nvars; 12864 vars = consdata->vars; 12865 weights = consdata->weights; 12866 12867 /* Check, whether linear knapsack can be upgraded to a cardinality constraint: 12868 * - all variables must be binary (always true) 12869 * - all coefficients must be 1.0 12870 * - the right hand side must be smaller than nvars 12871 */ 12872 if ( consdata->capacity >= nvars ) 12873 continue; 12874 12875 /* the weights are sorted: check first and last weight */ 12876 assert( consdata->sorted ); 12877 if ( weights[0] != 1 || weights[nvars-1] != 1 ) 12878 continue; 12879 12880 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */ 12881 for (v = 0; v < nvars; ++v) 12882 { 12883 SCIP_BOUNDTYPE* impltypes; 12884 SCIP_Real* implbounds; 12885 SCIP_VAR** implvars; 12886 SCIP_VAR* var; 12887 int nimpls; 12888 int j; 12889 12890 var = consdata->vars[v]; 12891 assert( var != NULL ); 12892 assert( SCIPvarIsBinary(var) ); 12893 12894 /* ignore non-active variables */ 12895 if ( ! SCIPvarIsActive(var) ) 12896 break; 12897 12898 /* be sure that implication variable has zero objective */ 12899 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) ) 12900 break; 12901 12902 nimpls = SCIPvarGetNImpls(var, FALSE); 12903 implvars = SCIPvarGetImplVars(var, FALSE); 12904 implbounds = SCIPvarGetImplBounds(var, FALSE); 12905 impltypes = SCIPvarGetImplTypes(var, FALSE); 12906 12907 for (j = 0; j < nimpls; ++j) 12908 { 12909 /* be sure that continuous variable is fixed to 0 */ 12910 if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER ) 12911 continue; 12912 12913 /* cannot currently deal with nonzero fixings */ 12914 if ( ! SCIPisZero(scip, implbounds[j]) ) 12915 continue; 12916 12917 /* number of down locks should be one */ 12918 if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 ) 12919 continue; 12920 12921 cardvars[v] = implvars[j]; 12922 cardweights[v] = (SCIP_Real) v; 12923 12924 break; 12925 } 12926 12927 /* found no variable upper bound candidate -> exit */ 12928 if ( j >= nimpls ) 12929 break; 12930 } 12931 12932 /* did not find fitting variable upper bound for some variable -> exit */ 12933 if ( v < nvars ) 12934 break; 12935 12936 /* save number of knapsack constraints that can be upgraded to a cardinality constraint, 12937 * in which the binary variable is involved in */ 12938 if ( makeupgrade == 0 ) 12939 { 12940 for (v = 0; v < nvars; ++v) 12941 { 12942 if ( SCIPhashmapExists(varhash, vars[v]) ) 12943 { 12944 int image; 12945 12946 image = SCIPhashmapGetImageInt(varhash, vars[v]); 12947 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) ); 12948 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) ); 12949 } 12950 else 12951 { 12952 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) ); 12953 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) ); 12954 assert( SCIPhashmapExists(varhash, vars[v]) ); 12955 } 12956 } 12957 } 12958 else 12959 { 12960 SCIP_CONS* origcons; 12961 12962 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a 12963 * knapsack constraint coincides with the number of variable up locks */ 12964 for (v = 0; v < nvars; ++v) 12965 { 12966 assert( SCIPhashmapExists(varhash, vars[v]) ); 12967 if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) ) 12968 break; 12969 } 12970 if ( v < nvars ) 12971 break; 12972 12973 /* store that we have upgraded */ 12974 conshdlrdata->upgradedcard = TRUE; 12975 12976 /* at this point we found suitable variable upper bounds */ 12977 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons)); 12978 12979 /* create cardinality constraint */ 12980 assert( ! SCIPconsIsModifiable(cons) ); 12981 SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights, 12982 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), 12983 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), 12984 SCIPconsIsLocal(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) ); 12985 #ifdef SCIP_DEBUG 12986 SCIPprintCons(scip, cons, NULL); 12987 SCIPinfoMessage(scip, NULL, "\n"); 12988 SCIPprintCons(scip, cardcons, NULL); 12989 SCIPinfoMessage(scip, NULL, "\n"); 12990 #endif 12991 SCIP_CALL( SCIPaddCons(scip, cardcons) ); 12992 SCIP_CALL( SCIPreleaseCons(scip, &cardcons) ); 12993 ++(*nupgdconss); 12994 12995 /* delete oknapsack constraint */ 12996 SCIP_CALL( SCIPdelCons(scip, cons) ); 12997 ++(*ndelconss); 12998 12999 /* We need to disable the original knapsack constraint, since it might happen that the binary variables 13000 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated, 13001 * although the cardinality constraint is satisfied. */ 13002 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons)); 13003 assert( origcons != NULL ); 13004 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) ); 13005 13006 for (v = 0; v < nvars; ++v) 13007 { 13008 int image; 13009 13010 assert ( SCIPhashmapExists(varhash, vars[v]) ); 13011 image = SCIPhashmapGetImageInt(varhash, vars[v]); 13012 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) ); 13013 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) ); 13014 } 13015 } 13016 } 13017 } 13018 SCIPhashmapFree(&varhash); 13019 SCIPfreeBufferArray(scip, &cardweights); 13020 SCIPfreeBufferArray(scip, &cardvars); 13021 13022 if ( *nupgdconss > noldupgdconss ) 13023 success = TRUE; 13024 } 13025 #endif 13026 13027 if( cutoff ) 13028 *result = SCIP_CUTOFF; 13029 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds ) 13030 *result = SCIP_SUCCESS; 13031 else 13032 *result = SCIP_DIDNOTFIND; 13033 13034 return SCIP_OKAY; 13035 } 13036 13037 /** propagation conflict resolving method of constraint handler */ 13038 static 13039 SCIP_DECL_CONSRESPROP(consRespropKnapsack) 13040 { /*lint --e{715}*/ 13041 SCIP_CONSDATA* consdata; 13042 SCIP_Longint capsum; 13043 int i; 13044 13045 assert(result != NULL); 13046 13047 consdata = SCIPconsGetData(cons); 13048 assert(consdata != NULL); 13049 13050 /* check if we fixed a binary variable to one (due to negated clique) */ 13051 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 ) 13052 { 13053 for( i = 0; i < consdata->nvars; ++i ) 13054 { 13055 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo ) 13056 { 13057 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 ); 13058 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) ); 13059 break; 13060 } 13061 } 13062 assert(i < consdata->nvars); 13063 } 13064 else 13065 { 13066 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of 13067 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the 13068 * knapsack constraint, see one above call of SCIPinferBinvarCons 13069 */ 13070 if( inferinfo < 0 ) 13071 capsum = 0; 13072 else 13073 { 13074 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0; 13075 * inferinfo stores the position of the inference variable (but maybe the variables were resorted) 13076 */ 13077 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar ) 13078 capsum = consdata->weights[inferinfo]; 13079 else 13080 { 13081 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i ) 13082 {} 13083 assert(i < consdata->nvars); 13084 capsum = consdata->weights[i]; 13085 } 13086 } 13087 13088 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds 13089 * the capacity 13090 */ 13091 if( capsum <= consdata->capacity ) 13092 { 13093 for( i = 0; i < consdata->nvars; i++ ) 13094 { 13095 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 ) 13096 { 13097 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) ); 13098 capsum += consdata->weights[i]; 13099 if( capsum > consdata->capacity ) 13100 break; 13101 } 13102 } 13103 } 13104 } 13105 13106 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable 13107 * to zero can included negated clique information. A negated clique means, that at most one of the clique 13108 * variables can be zero. These information can be used to compute a minimum activity of the constraint and 13109 * used to fix variables to zero. 13110 * 13111 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based 13112 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to 13113 * one. 13114 */ 13115 *result = SCIP_SUCCESS; 13116 13117 return SCIP_OKAY; 13118 } 13119 13120 /** variable rounding lock method of constraint handler */ 13121 /**! [SnippetConsLockKnapsack] */ 13122 static 13123 SCIP_DECL_CONSLOCK(consLockKnapsack) 13124 { /*lint --e{715}*/ 13125 SCIP_CONSDATA* consdata; 13126 int i; 13127 13128 consdata = SCIPconsGetData(cons); 13129 assert(consdata != NULL); 13130 13131 for( i = 0; i < consdata->nvars; i++) 13132 { 13133 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) ); 13134 } 13135 13136 return SCIP_OKAY; 13137 } 13138 /**! [SnippetConsLockKnapsack] */ 13139 13140 /** constraint activation notification method of constraint handler */ 13141 static 13142 SCIP_DECL_CONSACTIVE(consActiveKnapsack) 13143 { /*lint --e{715}*/ 13144 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisNLPConstructed(scip) ) 13145 { 13146 SCIP_CALL( addNlrow(scip, cons) ); 13147 } 13148 13149 return SCIP_OKAY; 13150 } 13151 13152 /** constraint deactivation notification method of constraint handler */ 13153 static 13154 SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack) 13155 { /*lint --e{715}*/ 13156 SCIP_CONSDATA* consdata; 13157 13158 assert(cons != NULL); 13159 13160 consdata = SCIPconsGetData(cons); 13161 assert(consdata != NULL); 13162 13163 /* remove row from NLP, if still in solving 13164 * if we are in exitsolve, the whole NLP will be freed anyway 13165 */ 13166 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL ) 13167 { 13168 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) ); 13169 } 13170 13171 return SCIP_OKAY; 13172 } 13173 13174 /** variable deletion method of constraint handler */ 13175 static 13176 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack) 13177 { 13178 assert(scip != NULL); 13179 assert(conshdlr != NULL); 13180 assert(conss != NULL || nconss == 0); 13181 13182 if( nconss > 0 ) 13183 { 13184 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) ); 13185 } 13186 13187 return SCIP_OKAY; 13188 } 13189 13190 /** constraint display method of constraint handler */ 13191 static 13192 SCIP_DECL_CONSPRINT(consPrintKnapsack) 13193 { /*lint --e{715}*/ 13194 SCIP_CONSDATA* consdata; 13195 int i; 13196 13197 assert( scip != NULL ); 13198 assert( conshdlr != NULL ); 13199 assert( cons != NULL ); 13200 13201 consdata = SCIPconsGetData(cons); 13202 assert(consdata != NULL); 13203 13204 for( i = 0; i < consdata->nvars; ++i ) 13205 { 13206 if( i > 0 ) 13207 SCIPinfoMessage(scip, file, " "); 13208 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]); 13209 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) ); 13210 } 13211 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity); 13212 13213 return SCIP_OKAY; 13214 } 13215 13216 /** constraint copying method of constraint handler */ 13217 static 13218 SCIP_DECL_CONSCOPY(consCopyKnapsack) 13219 { /*lint --e{715}*/ 13220 SCIP_VAR** sourcevars; 13221 SCIP_Longint* weights; 13222 SCIP_Real* coefs; 13223 const char* consname; 13224 int nvars; 13225 int v; 13226 13227 /* get variables and coefficients of the source constraint */ 13228 sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons); 13229 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons); 13230 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons); 13231 13232 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) ); 13233 for( v = 0; v < nvars; ++v ) 13234 coefs[v] = (SCIP_Real) weights[v]; 13235 13236 if( name != NULL ) 13237 consname = name; 13238 else 13239 consname = SCIPconsGetName(sourcecons); 13240 13241 /* copy the logic using the linear constraint copy method */ 13242 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs, 13243 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap, 13244 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) ); 13245 assert(cons != NULL); 13246 13247 SCIPfreeBufferArray(scip, &coefs); 13248 13249 return SCIP_OKAY; 13250 } 13251 13252 /** constraint parsing method of constraint handler */ 13253 static 13254 SCIP_DECL_CONSPARSE(consParseKnapsack) 13255 { /*lint --e{715}*/ 13256 SCIP_VAR* var; 13257 SCIP_Longint weight; 13258 SCIP_VAR** vars; 13259 SCIP_Longint* weights; 13260 SCIP_Longint capacity; 13261 char* endptr; 13262 int nread; 13263 int nvars; 13264 int varssize; 13265 13266 assert(scip != NULL); 13267 assert(success != NULL); 13268 assert(str != NULL); 13269 assert(name != NULL); 13270 assert(cons != NULL); 13271 13272 *success = TRUE; 13273 13274 nvars = 0; 13275 varssize = 5; 13276 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) ); 13277 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) ); 13278 13279 while( *str != '\0' ) 13280 { 13281 /* try to parse coefficient, and use 1 if not successful */ 13282 weight = 1; 13283 nread = 0; 13284 sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread); 13285 str += nread; 13286 13287 /* parse variable name */ 13288 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) ); 13289 13290 if( var == NULL ) 13291 { 13292 endptr = strchr(endptr, '<'); 13293 13294 if( endptr == NULL ) 13295 { 13296 SCIPerrorMessage("no capacity found\n"); 13297 *success = FALSE; 13298 } 13299 else 13300 str = endptr; 13301 13302 break; 13303 } 13304 13305 str = endptr; 13306 13307 /* store weight and variable */ 13308 if( varssize <= nvars ) 13309 { 13310 varssize = SCIPcalcMemGrowSize(scip, varssize+1); 13311 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) ); 13312 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) ); 13313 } 13314 13315 vars[nvars] = var; 13316 weights[nvars] = weight; 13317 ++nvars; 13318 13319 /* skip whitespace */ 13320 SCIP_CALL( SCIPskipSpace((char**)&str) ); 13321 } 13322 13323 if( *success ) 13324 { 13325 if( strncmp(str, "<=", 2) != 0 ) 13326 { 13327 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str); 13328 *success = FALSE; 13329 } 13330 else 13331 { 13332 str += 2; 13333 } 13334 } 13335 13336 if( *success ) 13337 { 13338 /* skip whitespace */ 13339 SCIP_CALL( SCIPskipSpace((char**)&str) ); 13340 13341 /* coverity[secure_coding] */ 13342 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 ) 13343 { 13344 SCIPerrorMessage("error parsing capacity from '%s'\n", str); 13345 *success = FALSE; 13346 } 13347 else 13348 { 13349 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity, 13350 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) ); 13351 } 13352 } 13353 13354 SCIPfreeBufferArray(scip, &vars); 13355 SCIPfreeBufferArray(scip, &weights); 13356 13357 return SCIP_OKAY; 13358 } 13359 13360 /** constraint method of constraint handler which returns the variables (if possible) */ 13361 static 13362 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack) 13363 { /*lint --e{715}*/ 13364 SCIP_CONSDATA* consdata; 13365 13366 consdata = SCIPconsGetData(cons); 13367 assert(consdata != NULL); 13368 13369 if( varssize < consdata->nvars ) 13370 (*success) = FALSE; 13371 else 13372 { 13373 assert(vars != NULL); 13374 13375 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars); 13376 (*success) = TRUE; 13377 } 13378 13379 return SCIP_OKAY; 13380 } 13381 13382 /** constraint method of constraint handler which returns the number of variables (if possible) */ 13383 static 13384 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack) 13385 { /*lint --e{715}*/ 13386 SCIP_CONSDATA* consdata; 13387 13388 consdata = SCIPconsGetData(cons); 13389 assert(consdata != NULL); 13390 13391 (*nvars) = consdata->nvars; 13392 (*success) = TRUE; 13393 13394 return SCIP_OKAY; 13395 } 13396 13397 /** constraint handler method which returns the permutation symmetry detection graph of a constraint */ 13398 static 13399 SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack) 13400 { /*lint --e{715}*/ 13401 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) ); 13402 13403 return SCIP_OKAY; 13404 } 13405 13406 /** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */ 13407 static 13408 SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack) 13409 { /*lint --e{715}*/ 13410 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) ); 13411 13412 return SCIP_OKAY; 13413 } 13414 13415 /* 13416 * Event handler 13417 */ 13418 13419 /** execution method of bound change event handler */ 13420 static 13421 SCIP_DECL_EVENTEXEC(eventExecKnapsack) 13422 { /*lint --e{715}*/ 13423 SCIP_CONSDATA* consdata; 13424 13425 assert(eventdata != NULL); 13426 assert(eventdata->cons != NULL); 13427 13428 consdata = SCIPconsGetData(eventdata->cons); 13429 assert(consdata != NULL); 13430 13431 switch( SCIPeventGetType(event) ) 13432 { 13433 case SCIP_EVENTTYPE_LBTIGHTENED: 13434 consdata->onesweightsum += eventdata->weight; 13435 consdata->presolvedtiming = 0; 13436 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) ); 13437 break; 13438 case SCIP_EVENTTYPE_LBRELAXED: 13439 consdata->onesweightsum -= eventdata->weight; 13440 break; 13441 case SCIP_EVENTTYPE_UBTIGHTENED: 13442 consdata->presolvedtiming = 0; 13443 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) ); 13444 break; 13445 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */ 13446 if( !consdata->existmultaggr ) 13447 { 13448 SCIP_VAR* var; 13449 var = SCIPeventGetVar(event); 13450 assert(var != NULL); 13451 13452 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */ 13453 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR ) 13454 { 13455 consdata->existmultaggr = TRUE; 13456 consdata->merged = FALSE; 13457 } 13458 else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED || 13459 (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED && SCIPvarGetStatus(SCIPvarGetNegatedVar(var)) == SCIP_VARSTATUS_AGGREGATED) ) 13460 consdata->merged = FALSE; 13461 } 13462 /*lint -fallthrough*/ 13463 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */ 13464 consdata->presolvedtiming = 0; 13465 break; 13466 case SCIP_EVENTTYPE_VARDELETED: 13467 consdata->varsdeleted = TRUE; 13468 break; 13469 default: 13470 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event)); 13471 return SCIP_INVALIDDATA; 13472 } 13473 13474 return SCIP_OKAY; 13475 } 13476 13477 13478 /* 13479 * constraint specific interface methods 13480 */ 13481 13482 /** creates the handler for knapsack constraints and includes it in SCIP */ 13483 SCIP_RETCODE SCIPincludeConshdlrKnapsack( 13484 SCIP* scip /**< SCIP data structure */ 13485 ) 13486 { 13487 SCIP_EVENTHDLRDATA* eventhdlrdata; 13488 SCIP_CONSHDLRDATA* conshdlrdata; 13489 SCIP_CONSHDLR* conshdlr; 13490 13491 /* create knapsack constraint handler data */ 13492 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) ); 13493 13494 /* include event handler for bound change events */ 13495 eventhdlrdata = NULL; 13496 conshdlrdata->eventhdlr = NULL; 13497 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC, 13498 eventExecKnapsack, eventhdlrdata) ); 13499 13500 /* get event handler for bound change events */ 13501 if( conshdlrdata->eventhdlr == NULL ) 13502 { 13503 SCIPerrorMessage("event handler for knapsack constraints not found\n"); 13504 return SCIP_PLUGINNOTFOUND; 13505 } 13506 13507 /* include constraint handler */ 13508 SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC, 13509 CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS, 13510 consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack, 13511 conshdlrdata) ); 13512 13513 assert(conshdlr != NULL); 13514 13515 /* set non-fundamental callbacks via specific setter functions */ 13516 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) ); 13517 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) ); 13518 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) ); 13519 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) ); 13520 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) ); 13521 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) ); 13522 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) ); 13523 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) ); 13524 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) ); 13525 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) ); 13526 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) ); 13527 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) ); 13528 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) ); 13529 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) ); 13530 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) ); 13531 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) ); 13532 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) ); 13533 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) ); 13534 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP, 13535 CONSHDLR_PROP_TIMING) ); 13536 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) ); 13537 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ, 13538 CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) ); 13539 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) ); 13540 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) ); 13541 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) ); 13542 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) ); 13543 13544 if( SCIPfindConshdlr(scip,"linear") != NULL ) 13545 { 13546 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */ 13547 SCIP_CALL( SCIPincludeLinconsUpgrade(scip, linconsUpgdKnapsack, LINCONSUPGD_PRIORITY, CONSHDLR_NAME) ); 13548 } 13549 13550 /* add knapsack constraint handler parameters */ 13551 SCIP_CALL( SCIPaddIntParam(scip, 13552 "constraints/" CONSHDLR_NAME "/sepacardfreq", 13553 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)", 13554 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) ); 13555 SCIP_CALL( SCIPaddRealParam(scip, 13556 "constraints/" CONSHDLR_NAME "/maxcardbounddist", 13557 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts", 13558 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) ); 13559 SCIP_CALL( SCIPaddRealParam(scip, 13560 "constraints/" CONSHDLR_NAME "/cliqueextractfactor", 13561 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)", 13562 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) ); 13563 SCIP_CALL( SCIPaddIntParam(scip, 13564 "constraints/" CONSHDLR_NAME "/maxrounds", 13565 "maximal number of separation rounds per node (-1: unlimited)", 13566 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) ); 13567 SCIP_CALL( SCIPaddIntParam(scip, 13568 "constraints/" CONSHDLR_NAME "/maxroundsroot", 13569 "maximal number of separation rounds per node in the root node (-1: unlimited)", 13570 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) ); 13571 SCIP_CALL( SCIPaddIntParam(scip, 13572 "constraints/" CONSHDLR_NAME "/maxsepacuts", 13573 "maximal number of cuts separated per separation round", 13574 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) ); 13575 SCIP_CALL( SCIPaddIntParam(scip, 13576 "constraints/" CONSHDLR_NAME "/maxsepacutsroot", 13577 "maximal number of cuts separated per separation round in the root node", 13578 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) ); 13579 SCIP_CALL( SCIPaddBoolParam(scip, 13580 "constraints/" CONSHDLR_NAME "/disaggregation", 13581 "should disaggregation of knapsack constraints be allowed in preprocessing?", 13582 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) ); 13583 SCIP_CALL( SCIPaddBoolParam(scip, 13584 "constraints/" CONSHDLR_NAME "/simplifyinequalities", 13585 "should presolving try to simplify knapsacks", 13586 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) ); 13587 SCIP_CALL( SCIPaddBoolParam(scip, 13588 "constraints/" CONSHDLR_NAME "/negatedclique", 13589 "should negated clique information be used in solving process", 13590 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) ); 13591 SCIP_CALL( SCIPaddBoolParam(scip, 13592 "constraints/" CONSHDLR_NAME "/presolpairwise", 13593 "should pairwise constraint comparison be performed in presolving?", 13594 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) ); 13595 SCIP_CALL( SCIPaddBoolParam(scip, 13596 "constraints/" CONSHDLR_NAME "/presolusehashing", 13597 "should hash table be used for detecting redundant constraints in advance", 13598 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) ); 13599 SCIP_CALL( SCIPaddBoolParam(scip, 13600 "constraints/" CONSHDLR_NAME "/dualpresolving", 13601 "should dual presolving steps be performed?", 13602 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) ); 13603 SCIP_CALL( SCIPaddBoolParam(scip, 13604 "constraints/" CONSHDLR_NAME "/usegubs", 13605 "should GUB information be used for separation?", 13606 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) ); 13607 SCIP_CALL( SCIPaddBoolParam(scip, 13608 "constraints/" CONSHDLR_NAME "/detectcutoffbound", 13609 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?", 13610 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) ); 13611 SCIP_CALL( SCIPaddBoolParam(scip, 13612 "constraints/" CONSHDLR_NAME "/detectlowerbound", 13613 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?", 13614 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) ); 13615 SCIP_CALL( SCIPaddBoolParam(scip, 13616 "constraints/" CONSHDLR_NAME "/updatecliquepartitions", 13617 "should clique partition information be updated when old partition seems outdated?", 13618 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) ); 13619 SCIP_CALL( SCIPaddRealParam(scip, 13620 "constraints/" CONSHDLR_NAME "/clqpartupdatefac", 13621 "factor on the growth of global cliques to decide when to update a previous " 13622 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)", 13623 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) ); 13624 #ifdef WITH_CARDINALITY_UPGRADE 13625 SCIP_CALL( SCIPaddBoolParam(scip, 13626 "constraints/" CONSHDLR_NAME "/upgdcardinality", 13627 "if TRUE then try to update knapsack constraints to cardinality constraints", 13628 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) ); 13629 #endif 13630 return SCIP_OKAY; 13631 } 13632 13633 /** creates and captures a knapsack constraint 13634 * 13635 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 13636 */ 13637 /**! [SnippetConsCreationKnapsack] */ 13638 SCIP_RETCODE SCIPcreateConsKnapsack( 13639 SCIP* scip, /**< SCIP data structure */ 13640 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 13641 const char* name, /**< name of constraint */ 13642 int nvars, /**< number of items in the knapsack */ 13643 SCIP_VAR** vars, /**< array with item variables */ 13644 SCIP_Longint* weights, /**< array with item weights */ 13645 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */ 13646 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? 13647 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ 13648 SCIP_Bool separate, /**< should the constraint be separated during LP processing? 13649 * Usually set to TRUE. */ 13650 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? 13651 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 13652 SCIP_Bool check, /**< should the constraint be checked for feasibility? 13653 * TRUE for model constraints, FALSE for additional, redundant constraints. */ 13654 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? 13655 * Usually set to TRUE. */ 13656 SCIP_Bool local, /**< is constraint only valid locally? 13657 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ 13658 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? 13659 * Usually set to FALSE. In column generation applications, set to TRUE if pricing 13660 * adds coefficients to this constraint. */ 13661 SCIP_Bool dynamic, /**< is constraint subject to aging? 13662 * Usually set to FALSE. Set to TRUE for own cuts which 13663 * are separated as constraints. */ 13664 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? 13665 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ 13666 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even 13667 * if it may be moved to a more global node? 13668 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ 13669 ) 13670 { 13671 SCIP_CONSHDLRDATA* conshdlrdata; 13672 SCIP_CONSHDLR* conshdlr; 13673 SCIP_CONSDATA* consdata; 13674 13675 /* find the knapsack constraint handler */ 13676 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME); 13677 if( conshdlr == NULL ) 13678 { 13679 SCIPerrorMessage("knapsack constraint handler not found\n"); 13680 return SCIP_PLUGINNOTFOUND; 13681 } 13682 13683 /* get event handler */ 13684 conshdlrdata = SCIPconshdlrGetData(conshdlr); 13685 assert(conshdlrdata != NULL); 13686 assert(conshdlrdata->eventhdlr != NULL); 13687 13688 /* create constraint data */ 13689 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) ); 13690 13691 /* create constraint */ 13692 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate, 13693 local, modifiable, dynamic, removable, stickingatnode) ); 13694 13695 /* catch events for variables */ 13696 if( SCIPisTransformed(scip) ) 13697 { 13698 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) ); 13699 } 13700 13701 return SCIP_OKAY; 13702 } 13703 /**! [SnippetConsCreationKnapsack] */ 13704 13705 /** creates and captures a knapsack constraint 13706 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the 13707 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h 13708 * 13709 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration 13710 * 13711 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons() 13712 */ 13713 SCIP_RETCODE SCIPcreateConsBasicKnapsack( 13714 SCIP* scip, /**< SCIP data structure */ 13715 SCIP_CONS** cons, /**< pointer to hold the created constraint */ 13716 const char* name, /**< name of constraint */ 13717 int nvars, /**< number of items in the knapsack */ 13718 SCIP_VAR** vars, /**< array with item variables */ 13719 SCIP_Longint* weights, /**< array with item weights */ 13720 SCIP_Longint capacity /**< capacity of knapsack */ 13721 ) 13722 { 13723 assert(scip != NULL); 13724 13725 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity, 13726 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); 13727 13728 return SCIP_OKAY; 13729 } 13730 13731 /** adds new item to knapsack constraint */ 13732 SCIP_RETCODE SCIPaddCoefKnapsack( 13733 SCIP* scip, /**< SCIP data structure */ 13734 SCIP_CONS* cons, /**< constraint data */ 13735 SCIP_VAR* var, /**< item variable */ 13736 SCIP_Longint weight /**< item weight */ 13737 ) 13738 { 13739 assert(var != NULL); 13740 assert(scip != NULL); 13741 13742 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13743 { 13744 SCIPerrorMessage("constraint is not a knapsack constraint\n"); 13745 return SCIP_INVALIDDATA; 13746 } 13747 13748 SCIP_CALL( addCoef(scip, cons, var, weight) ); 13749 13750 return SCIP_OKAY; 13751 } 13752 13753 /** gets the capacity of the knapsack constraint */ 13754 SCIP_Longint SCIPgetCapacityKnapsack( 13755 SCIP* scip, /**< SCIP data structure */ 13756 SCIP_CONS* cons /**< constraint data */ 13757 ) 13758 { 13759 SCIP_CONSDATA* consdata; 13760 13761 assert(scip != NULL); 13762 13763 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13764 { 13765 SCIPerrorMessage("constraint is not a knapsack constraint\n"); 13766 SCIPABORT(); 13767 return 0; /*lint !e527*/ 13768 } 13769 13770 consdata = SCIPconsGetData(cons); 13771 assert(consdata != NULL); 13772 13773 return consdata->capacity; 13774 } 13775 13776 /** changes capacity of the knapsack constraint 13777 * 13778 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM) 13779 */ 13780 SCIP_RETCODE SCIPchgCapacityKnapsack( 13781 SCIP* scip, /**< SCIP data structure */ 13782 SCIP_CONS* cons, /**< constraint data */ 13783 SCIP_Longint capacity /**< new capacity of knapsack */ 13784 ) 13785 { 13786 SCIP_CONSDATA* consdata; 13787 13788 assert(scip != NULL); 13789 13790 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13791 { 13792 SCIPerrorMessage("constraint is not a knapsack constraint\n"); 13793 return SCIP_INVALIDDATA; 13794 } 13795 13796 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM ) 13797 { 13798 SCIPerrorMessage("method can only be called during problem creation stage\n"); 13799 return SCIP_INVALIDDATA; 13800 } 13801 13802 consdata = SCIPconsGetData(cons); 13803 assert(consdata != NULL); 13804 13805 consdata->capacity = capacity; 13806 13807 return SCIP_OKAY; 13808 } 13809 13810 /** gets the number of items in the knapsack constraint */ 13811 int SCIPgetNVarsKnapsack( 13812 SCIP* scip, /**< SCIP data structure */ 13813 SCIP_CONS* cons /**< constraint data */ 13814 ) 13815 { 13816 SCIP_CONSDATA* consdata; 13817 13818 assert(scip != NULL); 13819 13820 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13821 { 13822 SCIPerrorMessage("constraint is not a knapsack constraint\n"); 13823 SCIPABORT(); 13824 return -1; /*lint !e527*/ 13825 } 13826 13827 consdata = SCIPconsGetData(cons); 13828 assert(consdata != NULL); 13829 13830 return consdata->nvars; 13831 } 13832 13833 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */ 13834 SCIP_VAR** SCIPgetVarsKnapsack( 13835 SCIP* scip, /**< SCIP data structure */ 13836 SCIP_CONS* cons /**< constraint data */ 13837 ) 13838 { 13839 SCIP_CONSDATA* consdata; 13840 13841 assert(scip != NULL); 13842 13843 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13844 { 13845 SCIPerrorMessage("constraint is not a knapsack constraint\n"); 13846 SCIPABORT(); 13847 return NULL; /*lint !e527*/ 13848 } 13849 13850 consdata = SCIPconsGetData(cons); 13851 assert(consdata != NULL); 13852 13853 return consdata->vars; 13854 } 13855 13856 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */ 13857 SCIP_Longint* SCIPgetWeightsKnapsack( 13858 SCIP* scip, /**< SCIP data structure */ 13859 SCIP_CONS* cons /**< constraint data */ 13860 ) 13861 { 13862 SCIP_CONSDATA* consdata; 13863 13864 assert(scip != NULL); 13865 13866 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13867 { 13868 SCIPerrorMessage("constraint is not a knapsack constraint\n"); 13869 SCIPABORT(); 13870 return NULL; /*lint !e527*/ 13871 } 13872 13873 consdata = SCIPconsGetData(cons); 13874 assert(consdata != NULL); 13875 13876 return consdata->weights; 13877 } 13878 13879 /** gets the dual solution of the knapsack constraint in the current LP */ 13880 SCIP_Real SCIPgetDualsolKnapsack( 13881 SCIP* scip, /**< SCIP data structure */ 13882 SCIP_CONS* cons /**< constraint data */ 13883 ) 13884 { 13885 SCIP_CONSDATA* consdata; 13886 13887 assert(scip != NULL); 13888 13889 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13890 { 13891 SCIPerrorMessage("constraint is not a knapsack constraint\n"); 13892 SCIPABORT(); 13893 return SCIP_INVALID; /*lint !e527*/ 13894 } 13895 13896 consdata = SCIPconsGetData(cons); 13897 assert(consdata != NULL); 13898 13899 if( consdata->row != NULL ) 13900 return SCIProwGetDualsol(consdata->row); 13901 else 13902 return 0.0; 13903 } 13904 13905 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */ 13906 SCIP_Real SCIPgetDualfarkasKnapsack( 13907 SCIP* scip, /**< SCIP data structure */ 13908 SCIP_CONS* cons /**< constraint data */ 13909 ) 13910 { 13911 SCIP_CONSDATA* consdata; 13912 13913 assert(scip != NULL); 13914 13915 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13916 { 13917 SCIPerrorMessage("constraint is not a knapsack constraint\n"); 13918 SCIPABORT(); 13919 return SCIP_INVALID; /*lint !e527*/ 13920 } 13921 13922 consdata = SCIPconsGetData(cons); 13923 assert(consdata != NULL); 13924 13925 if( consdata->row != NULL ) 13926 return SCIProwGetDualfarkas(consdata->row); 13927 else 13928 return 0.0; 13929 } 13930 13931 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created; 13932 * the user must not modify the row! 13933 */ 13934 SCIP_ROW* SCIPgetRowKnapsack( 13935 SCIP* scip, /**< SCIP data structure */ 13936 SCIP_CONS* cons /**< constraint data */ 13937 ) 13938 { 13939 SCIP_CONSDATA* consdata; 13940 13941 assert(scip != NULL); 13942 13943 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 ) 13944 { 13945 SCIPerrorMessage("constraint is not a knapsack\n"); 13946 SCIPABORT(); 13947 return NULL; /*lint !e527*/ 13948 } 13949 13950 consdata = SCIPconsGetData(cons); 13951 assert(consdata != NULL); 13952 13953 return consdata->row; 13954 } 13955 13956 /** cleans up (multi-)aggregations and fixings from knapsack constraints */ 13957 SCIP_RETCODE SCIPcleanupConssKnapsack( 13958 SCIP* scip, /**< SCIP data structure */ 13959 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */ 13960 SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */ 13961 ) 13962 { 13963 SCIP_CONSHDLR* conshdlr; 13964 SCIP_CONS** conss; 13965 int nconss; 13966 int i; 13967 13968 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME); 13969 if( conshdlr == NULL ) 13970 return SCIP_OKAY; 13971 13972 assert(infeasible != NULL); 13973 *infeasible = FALSE; 13974 13975 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr); 13976 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr); 13977 13978 for( i = 0; i < nconss; ++i ) 13979 { 13980 SCIP_CALL( applyFixings(scip, conss[i], infeasible) ); 13981 13982 if( *infeasible ) 13983 break; 13984 } 13985 13986 return SCIP_OKAY; 13987 } 13988