SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cons_knapsack.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_knapsack.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
28 * @author Tobias Achterberg
29 * @author Xin Liu
30 * @author Kati Wolter
31 * @author Michael Winkler
32 * @author Tobias Fischer
33 */
34
35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36
38#include "scip/cons_knapsack.h"
39#include "scip/cons_linear.h"
40#include "scip/cons_logicor.h"
41#include "scip/cons_setppc.h"
42#include "scip/pub_cons.h"
43#include "scip/pub_event.h"
44#include "scip/pub_implics.h"
45#include "scip/pub_lp.h"
46#include "scip/pub_message.h"
47#include "scip/pub_misc.h"
49#include "scip/pub_misc_sort.h"
50#include "scip/pub_sepa.h"
51#include "scip/pub_var.h"
52#include "scip/scip_branch.h"
53#include "scip/scip_conflict.h"
54#include "scip/scip_cons.h"
55#include "scip/scip_copy.h"
56#include "scip/scip_cut.h"
57#include "scip/scip_event.h"
58#include "scip/scip_general.h"
59#include "scip/scip_lp.h"
60#include "scip/scip_mem.h"
61#include "scip/scip_message.h"
62#include "scip/scip_nlp.h"
63#include "scip/scip_numerics.h"
64#include "scip/scip_param.h"
65#include "scip/scip_prob.h"
66#include "scip/scip_probing.h"
67#include "scip/scip_sol.h"
69#include "scip/scip_tree.h"
70#include "scip/scip_var.h"
71#include "scip/symmetry_graph.h"
73#include <ctype.h>
74#include <string.h>
75
76#ifdef WITH_CARDINALITY_UPGRADE
78#endif
79
80/* constraint handler properties */
81#define CONSHDLR_NAME "knapsack"
82#define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
83#define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
84#define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
85#define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
86#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
87#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
88#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
89 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
90#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
91#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
92#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
93#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
94
95#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
96#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
97
98#define EVENTHDLR_NAME "knapsack"
99#define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
100#define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
101 | SCIP_EVENTTYPE_UBTIGHTENED \
102 | SCIP_EVENTTYPE_VARFIXED \
103 | SCIP_EVENTTYPE_VARDELETED \
104 | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
105
106#define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
107
108#define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
109#define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
110
111#define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
112#define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
113#define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
114
115#define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
116#define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
117#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
118#define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
119#define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
120#define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
121 * to best node's dual bound for separating knapsack cuts */
122#define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
123#define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
124#define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
125
126#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
127#define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
128
129#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
130#define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
131
132#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
133#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
134#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
135 * comparison round */
136#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
137#define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
138 * function defining an upper bound and prevent these constraints from
139 * entering the LP */
140#define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
141 * function defining a lower bound and prevent these constraints from
142 * entering the LP */
143#define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
144#define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
145
146#define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
147#define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
148#define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
149#define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
150 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
151#define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
152#define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
153#ifdef WITH_CARDINALITY_UPGRADE
154#define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
155#endif
156
157/* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
158
159/*
160 * Data structures
161 */
162
163/** constraint handler data */
164struct SCIP_ConshdlrData
165{
166 int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
167 * you have to clear it at the end, exists only in presolving stage */
168 int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
169 * you have to clear it at the end, exists only in presolving stage */
170 SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
171 * you have to clear it at the end, exists only in presolving stage */
172 SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
173 * you have to clear it at the end, exists only in presolving stage */
174 SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
175 * you have to clear it at the end, exists only in presolving stage */
176 SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
177 * you have to clear it at the end, exists only in presolving stage */
178 SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
179 * you have to clear it at the end, exists only in presolving stage */
180 SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
181 * you have to clear it at the end, exists only in presolving stage */
182 SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
183 * you have to clear it at the end */
184 int ints1size; /**< size of ints1 array */
185 int ints2size; /**< size of ints2 array */
186 int longints1size; /**< size of longints1 array */
187 int longints2size; /**< size of longints2 array */
188 int bools1size; /**< size of bools1 array */
189 int bools2size; /**< size of bools2 array */
190 int bools3size; /**< size of bools3 array */
191 int bools4size; /**< size of bools4 array */
192 int reals1size; /**< size of reals1 array */
193 int* probtoidxmap; /**< cleared memory array with default values -1; used for clique partitions */
194 int probtoidxmapsize; /**< size of probtoidxmap */
195 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
196 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
197 * to best node's dual bound for separating knapsack cuts */
198 int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
199 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
200 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
201 int maxsepacuts; /**< maximal number of cuts separated per separation round */
202 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
203 SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
204 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
205 SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
206 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
207 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
208 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
209 SCIP_Bool usegubs; /**< should GUB information be used for separation? */
210 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
211 * function defining an upper bound and prevent these constraints from
212 * entering the LP */
213 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
214 * function defining a lower bound and prevent these constraints from
215 * entering the LP */
216 SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
217 SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
218 SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
219 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
220#ifdef WITH_CARDINALITY_UPGRADE
221 SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
222 SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
223#endif
224};
225
226
227/** constraint data for knapsack constraints */
228struct SCIP_ConsData
229{
230 SCIP_VAR** vars; /**< variables in knapsack constraint */
231 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
232 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
233 int* cliquepartition; /**< clique indices of the clique partition */
234 int* negcliquepartition; /**< clique indices of the negated clique partition */
235 SCIP_ROW* row; /**< corresponding LP row */
236 SCIP_NLROW* nlrow; /**< corresponding NLP row */
237 int nvars; /**< number of variables in knapsack constraint */
238 int varssize; /**< size of vars, weights, and eventdata arrays */
239 int ncliques; /**< number of cliques in the clique partition */
240 int nnegcliques; /**< number of cliques in the negated clique partition */
241 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
242 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
243 SCIP_Longint capacity; /**< capacity of knapsack */
244 SCIP_Longint weightsum; /**< sum of all weights */
245 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
246 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
247 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
248 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
249 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
250 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
251 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
252 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
253 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
254};
255
256/** event data for bound changes events */
257struct SCIP_EventData
258{
259 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
260 SCIP_Longint weight; /**< weight of variable */
261 int filterpos; /**< position of event in variable's event filter */
262};
263
264
265/** data structure to combine two sorting key values */
266struct sortkeypair
267{
268 SCIP_Real key1; /**< first sort key value */
269 SCIP_Real key2; /**< second sort key value */
270};
271typedef struct sortkeypair SORTKEYPAIR;
272
273/** status of GUB constraint */
275{
276 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
277 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
278 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
279 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
280 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
281 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
282};
284
285/** status of variable in GUB constraint */
287{
288 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
289 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
290 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
291 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
292 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
293 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
294};
296
297/** data structure of GUB constraints */
299{
300 int* gubvars; /**< indices of GUB variables in knapsack constraint */
301 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
302 int ngubvars; /**< number of GUB variables */
303 int gubvarssize; /**< size of gubvars array */
304};
306
307/** data structure of a set of GUB constraints */
309{
310 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
311 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
312 int ngubconss; /**< number of GUB constraints */
313 int nvars; /**< number of variables in knapsack constraint */
314 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
315 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
316};
318
319/*
320 * Local methods
321 */
322
323/** comparison method for two sorting key pairs */
324static
325SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
326{
327 SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
328 SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
329
330 if( sortkeypair1->key1 < sortkeypair2->key1 )
331 return -1;
332 else if( sortkeypair1->key1 > sortkeypair2->key1 )
333 return +1;
334 else if( sortkeypair1->key2 < sortkeypair2->key2 )
335 return -1;
336 else if( sortkeypair1->key2 > sortkeypair2->key2 )
337 return +1;
338 else
339 return 0;
340}
341
342/** creates event data */
343static
345 SCIP* scip, /**< SCIP data structure */
346 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
347 SCIP_CONS* cons, /**< constraint */
348 SCIP_Longint weight /**< weight of variable */
349 )
350{
351 assert(eventdata != NULL);
352
353 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
354 (*eventdata)->cons = cons;
355 (*eventdata)->weight = weight;
356
357 return SCIP_OKAY;
358}
359
360/** frees event data */
361static
363 SCIP* scip, /**< SCIP data structure */
364 SCIP_EVENTDATA** eventdata /**< pointer to event data */
365 )
366{
367 assert(eventdata != NULL);
368
369 SCIPfreeBlockMemory(scip, eventdata);
370
371 return SCIP_OKAY;
372}
373
374/** sorts items in knapsack with nonincreasing weights */
375static
377 SCIP_CONSDATA* consdata /**< constraint data */
378 )
379{
380 assert(consdata != NULL);
381 assert(consdata->nvars == 0 || consdata->vars != NULL);
382 assert(consdata->nvars == 0 || consdata->weights != NULL);
383 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
384 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
385
386 if( !consdata->sorted )
387 {
388 int pos;
389 int lastcliquenum;
390 int v;
391
392 /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
393 * sorted by first array in non-increasing order via sort template */
395 consdata->weights,
396 (void**)consdata->vars,
397 (void**)consdata->eventdata,
398 consdata->cliquepartition,
399 consdata->negcliquepartition,
400 consdata->nvars);
401
402 v = consdata->nvars - 1;
403 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
404 while( v >= 0 )
405 {
406 int w = v - 1;
407
408 while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
409 --w;
410
411 if( v - w > 1 )
412 {
413 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
415 (void**)(&(consdata->vars[w+1])),
416 (void**)(&(consdata->eventdata[w+1])),
417 &(consdata->cliquepartition[w+1]),
418 &(consdata->negcliquepartition[w+1]),
419 SCIPvarComp,
420 v - w);
421 }
422 v = w;
423 }
424
425 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
426 if( consdata->cliquepartitioned )
427 {
428 lastcliquenum = 0;
429
430 for( pos = 0; pos < consdata->nvars; ++pos )
431 {
432 /* if the clique number in the normal clique at position pos is greater than the last found clique number the
433 * partition is invalid */
434 if( consdata->cliquepartition[pos] > lastcliquenum )
435 {
436 consdata->cliquepartitioned = FALSE;
437 break;
438 }
439 else if( consdata->cliquepartition[pos] == lastcliquenum )
440 ++lastcliquenum;
441 }
442 }
443 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
444 if( consdata->negcliquepartitioned )
445 {
446 lastcliquenum = 0;
447
448 for( pos = 0; pos < consdata->nvars; ++pos )
449 {
450 /* if the clique number in the negated clique at position pos is greater than the last found clique number the
451 * partition is invalid */
452 if( consdata->negcliquepartition[pos] > lastcliquenum )
453 {
454 consdata->negcliquepartitioned = FALSE;
455 break;
456 }
457 else if( consdata->negcliquepartition[pos] == lastcliquenum )
458 ++lastcliquenum;
459 }
460 }
461
462 consdata->sorted = TRUE;
463 }
464#ifndef NDEBUG
465 {
466 /* check if the weight array is sorted in a non-increasing way */
467 int i;
468 for( i = 0; i < consdata->nvars-1; ++i )
469 assert(consdata->weights[i] >= consdata->weights[i+1]);
470 }
471#endif
472}
473
474/** calculates a partition of the variables into cliques */
475static
477 SCIP* scip, /**< SCIP data structure */
478 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
479 SCIP_CONSDATA* consdata, /**< constraint data */
480 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
481 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
482 )
483{
484 SCIP_Bool ispartitionoutdated;
485 SCIP_Bool isnegpartitionoutdated;
486 assert(consdata != NULL);
487 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
488
489 /* rerun eventually if number of global cliques increased considerably since last partition */
490 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
491 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
492
493 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
494 {
495 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
496 consdata->cliquepartition, &consdata->ncliques) );
497 consdata->cliquepartitioned = TRUE;
498 consdata->ncliqueslastpart = SCIPgetNCliques(scip);
499 }
500
501 /* rerun eventually if number of global cliques increased considerably since last negated partition */
502 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
503 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
504
505 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
506 {
507 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
508 consdata->negcliquepartition, &consdata->nnegcliques) );
509 consdata->negcliquepartitioned = TRUE;
510 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
511 }
512 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
513 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
514
515 return SCIP_OKAY;
516}
517
518/** installs rounding locks for the given variable in the given knapsack constraint */
519static
521 SCIP* scip, /**< SCIP data structure */
522 SCIP_CONS* cons, /**< knapsack constraint */
523 SCIP_VAR* var /**< variable of constraint entry */
524 )
525{
527
528 return SCIP_OKAY;
529}
530
531/** removes rounding locks for the given variable in the given knapsack constraint */
532static
534 SCIP* scip, /**< SCIP data structure */
535 SCIP_CONS* cons, /**< knapsack constraint */
536 SCIP_VAR* var /**< variable of constraint entry */
537 )
538{
540
541 return SCIP_OKAY;
542}
543
544/** catches bound change events for variables in knapsack */
545static
547 SCIP* scip, /**< SCIP data structure */
548 SCIP_CONS* cons, /**< constraint */
549 SCIP_CONSDATA* consdata, /**< constraint data */
550 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
551 )
552{
553 int i;
554
555 assert(cons != NULL);
556 assert(consdata != NULL);
557 assert(consdata->nvars == 0 || consdata->vars != NULL);
558 assert(consdata->nvars == 0 || consdata->weights != NULL);
559 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
560
561 for( i = 0; i < consdata->nvars; i++)
562 {
563 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
565 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
566 }
567
568 return SCIP_OKAY;
569}
570
571/** drops bound change events for variables in knapsack */
572static
574 SCIP* scip, /**< SCIP data structure */
575 SCIP_CONSDATA* consdata, /**< constraint data */
576 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
577 )
578{
579 int i;
580
581 assert(consdata != NULL);
582 assert(consdata->nvars == 0 || consdata->vars != NULL);
583 assert(consdata->nvars == 0 || consdata->weights != NULL);
584 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
585
586 for( i = 0; i < consdata->nvars; i++)
587 {
589 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
590 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
591 }
592
593 return SCIP_OKAY;
594}
595
596/** ensures, that vars and vals arrays can store at least num entries */
597static
599 SCIP* scip, /**< SCIP data structure */
600 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
601 int num, /**< minimum number of entries to store */
602 SCIP_Bool transformed /**< is constraint from transformed problem? */
603 )
604{
605 assert(consdata != NULL);
606 assert(consdata->nvars <= consdata->varssize);
607
608 if( num > consdata->varssize )
609 {
610 int newsize;
611
612 newsize = SCIPcalcMemGrowSize(scip, num);
613 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
614 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
615 if( transformed )
616 {
617 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
618 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
619 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
620 }
621 else
622 {
623 assert(consdata->eventdata == NULL);
624 assert(consdata->cliquepartition == NULL);
625 assert(consdata->negcliquepartition == NULL);
626 }
627 consdata->varssize = newsize;
628 }
629 assert(num <= consdata->varssize);
630
631 return SCIP_OKAY;
632}
633
634/** updates all weight sums for fixed and unfixed variables */
635static
637 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
638 SCIP_VAR* var, /**< variable for this weight */
639 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
640 )
641{
642 assert(consdata != NULL);
643 assert(var != NULL);
644
645 consdata->weightsum += weightdelta;
646
647 if( SCIPvarGetLbLocal(var) > 0.5 )
648 consdata->onesweightsum += weightdelta;
649
650 assert(consdata->weightsum >= 0);
651 assert(consdata->onesweightsum >= 0);
652}
653
654/** creates knapsack constraint data */
655static
657 SCIP* scip, /**< SCIP data structure */
658 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
659 int nvars, /**< number of variables in knapsack */
660 SCIP_VAR** vars, /**< variables of knapsack */
661 SCIP_Longint* weights, /**< weights of knapsack items */
662 SCIP_Longint capacity /**< capacity of knapsack */
663 )
664{
665 int v;
666 SCIP_Longint constant;
667
668 assert(consdata != NULL);
669
670 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
671
672 constant = 0L;
673 (*consdata)->vars = NULL;
674 (*consdata)->weights = NULL;
675 (*consdata)->nvars = 0;
676 if( nvars > 0 )
677 {
678 SCIP_VAR** varsbuffer;
679 SCIP_Longint* weightsbuffer;
680 int k;
681
682 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
683 SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
684
685 k = 0;
686 for( v = 0; v < nvars; ++v )
687 {
688 assert(vars[v] != NULL);
690
691 /* all weight have to be non negative */
692 assert( weights[v] >= 0 );
693
694 if( weights[v] > 0 )
695 {
696 /* treat fixed variables as constants if problem compression is enabled */
698 {
699 /* only if the variable is fixed to 1, we add its weight to the constant */
700 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
701 constant += weights[v];
702 }
703 else
704 {
705 varsbuffer[k] = vars[v];
706 weightsbuffer[k] = weights[v];
707 ++k;
708 }
709 }
710 }
711 assert(k >= 0);
712 assert(constant >= 0);
713
714 (*consdata)->nvars = k;
715
716 /* copy the active variables and weights into the constraint data structure */
717 if( k > 0 )
718 {
719 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
720 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
721 }
722
723 /* free buffer storage */
724 SCIPfreeBufferArray(scip, &weightsbuffer);
725 SCIPfreeBufferArray(scip, &varsbuffer);
726 }
727
728 (*consdata)->varssize = (*consdata)->nvars;
729 (*consdata)->capacity = capacity - constant;
730 (*consdata)->eventdata = NULL;
731 (*consdata)->cliquepartition = NULL;
732 (*consdata)->negcliquepartition = NULL;
733 (*consdata)->row = NULL;
734 (*consdata)->nlrow = NULL;
735 (*consdata)->weightsum = 0;
736 (*consdata)->onesweightsum = 0;
737 (*consdata)->ncliques = 0;
738 (*consdata)->nnegcliques = 0;
739 (*consdata)->presolvedtiming = 0;
740 (*consdata)->sorted = FALSE;
741 (*consdata)->cliquepartitioned = FALSE;
742 (*consdata)->negcliquepartitioned = FALSE;
743 (*consdata)->ncliqueslastpart = -1;
744 (*consdata)->ncliqueslastnegpart = -1;
745 (*consdata)->merged = FALSE;
746 (*consdata)->cliquesadded = FALSE;
747 (*consdata)->varsdeleted = FALSE;
748 (*consdata)->existmultaggr = FALSE;
749
750 /* get transformed variables, if we are in the transformed problem */
752 {
753 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
754
755 for( v = 0; v < (*consdata)->nvars; v++ )
756 {
757 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
758 assert(var != NULL);
759 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
760 }
761
762 /* allocate memory for additional data structures */
763 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
764 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
765 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
766 }
767
768 /* calculate sum of weights and capture variables */
769 for( v = 0; v < (*consdata)->nvars; ++v )
770 {
771 /* calculate sum of weights */
772 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
773
774 /* capture variables */
775 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
776 }
777 return SCIP_OKAY;
778}
779
780/** frees knapsack constraint data */
781static
783 SCIP* scip, /**< SCIP data structure */
784 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
785 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
786 )
787{
788 assert(consdata != NULL);
789 assert(*consdata != NULL);
790
791 if( (*consdata)->row != NULL )
792 {
793 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
794 }
795 if( (*consdata)->nlrow != NULL )
796 {
797 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
798 }
799 if( (*consdata)->eventdata != NULL )
800 {
801 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
802 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
803 }
804 if( (*consdata)->negcliquepartition != NULL )
805 {
806 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
807 }
808 if( (*consdata)->cliquepartition != NULL )
809 {
810 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
811 }
812 if( (*consdata)->vars != NULL )
813 {
814 int v;
815
816 /* release variables */
817 for( v = 0; v < (*consdata)->nvars; v++ )
818 {
819 assert((*consdata)->vars[v] != NULL);
820 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
821 }
822
823 assert( (*consdata)->weights != NULL );
824 assert( (*consdata)->varssize > 0 );
825 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
826 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
827 }
828
829 SCIPfreeBlockMemory(scip, consdata);
830
831 return SCIP_OKAY;
832}
833
834/** changes a single weight in knapsack constraint data */
835static
837 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
838 int item, /**< item number */
839 SCIP_Longint newweight /**< new weight of item */
840 )
841{
842 SCIP_Longint oldweight;
843 SCIP_Longint weightdiff;
844
845 assert(consdata != NULL);
846 assert(0 <= item && item < consdata->nvars);
847
848 oldweight = consdata->weights[item];
849 weightdiff = newweight - oldweight;
850 consdata->weights[item] = newweight;
851
852 /* update weight sums for all and fixed variables */
853 updateWeightSums(consdata, consdata->vars[item], weightdiff);
854
855 if( consdata->eventdata != NULL )
856 {
857 assert(consdata->eventdata[item] != NULL);
858 assert(consdata->eventdata[item]->weight == oldweight);
859 consdata->eventdata[item]->weight = newweight;
860 }
861
862 consdata->presolvedtiming = 0;
863 consdata->sorted = FALSE;
864
865 /* recalculate cliques extraction after a weight was increased */
866 if( oldweight < newweight )
867 {
868 consdata->cliquesadded = FALSE;
869 }
870}
871
872/** creates LP row corresponding to knapsack constraint */
873static
875 SCIP* scip, /**< SCIP data structure */
876 SCIP_CONS* cons /**< knapsack constraint */
877 )
878{
879 SCIP_CONSDATA* consdata;
880 int i;
881
882 consdata = SCIPconsGetData(cons);
883 assert(consdata != NULL);
884 assert(consdata->row == NULL);
885
886 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
887 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
889
890 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
891 for( i = 0; i < consdata->nvars; ++i )
892 {
893 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
894 }
895 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
896
897 return SCIP_OKAY;
898}
899
900/** adds linear relaxation of knapsack constraint to the LP */
901static
903 SCIP* scip, /**< SCIP data structure */
904 SCIP_CONS* cons, /**< knapsack constraint */
905 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
906 )
907{
908 SCIP_CONSDATA* consdata;
909
910 assert( cutoff != NULL );
911 *cutoff = FALSE;
912
913 consdata = SCIPconsGetData(cons);
914 assert(consdata != NULL);
915
916 if( consdata->row == NULL )
917 {
919 }
920 assert(consdata->row != NULL);
921
922 /* insert LP row as cut */
923 if( !SCIProwIsInLP(consdata->row) )
924 {
925 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
926 SCIPconsGetName(cons), consdata->capacity);
927 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, consdata->row, NULL) ) );
928 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
929 }
930
931 return SCIP_OKAY;
932}
933
934/** adds knapsack constraint as row to the NLP, if not added yet */
935static
937 SCIP* scip, /**< SCIP data structure */
938 SCIP_CONS* cons /**< knapsack constraint */
939 )
940{
941 SCIP_CONSDATA* consdata;
942
944
945 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
946 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
947 return SCIP_OKAY;
948
949 consdata = SCIPconsGetData(cons);
950 assert(consdata != NULL);
951
952 if( consdata->nlrow == NULL )
953 {
954 SCIP_Real* coefs;
955 int i;
956
957 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
958 for( i = 0; i < consdata->nvars; ++i )
959 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
960
961 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
962 consdata->nvars, consdata->vars, coefs, NULL,
963 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
964
965 assert(consdata->nlrow != NULL);
966
967 SCIPfreeBufferArray(scip, &coefs);
968 }
969
970 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
971 {
972 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
973 }
974
975 return SCIP_OKAY;
976}
977
978/** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
979static
981 SCIP* scip, /**< SCIP data structure */
982 SCIP_CONS* cons, /**< constraint to check */
983 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
984 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
985 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
986 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
987 )
988{
989 SCIP_CONSDATA* consdata;
990
991 assert(violated != NULL);
992
993 consdata = SCIPconsGetData(cons);
994 assert(consdata != NULL);
995
996 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
997 SCIPconsGetName(cons), (void*)sol, checklprows);
998
999 *violated = FALSE;
1000
1001 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
1002 {
1003 SCIP_Real normsum = 0.0;
1004 SCIP_Real hugesum = 0.0;
1005 SCIP_Real absviol;
1006 SCIP_Real relviol;
1007 int v;
1008
1009 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1010 * enforcement
1011 */
1012 if( sol == NULL )
1013 {
1014 SCIP_CALL( SCIPincConsAge(scip, cons) );
1015 }
1016
1017 /* sum separately over normal and huge weight contributions in order to reduce numerical cancellation */
1018 for( v = consdata->nvars - 1; v >= 0; --v )
1019 {
1020 assert(SCIPvarIsBinary(consdata->vars[v]));
1021
1022 if( SCIPisHugeValue(scip, (SCIP_Real)consdata->weights[v]) )
1023 hugesum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1024 else
1025 normsum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1026 }
1027
1028 /* calculate constraint violation and update it in solution */
1029 normsum += hugesum;
1030
1031 if( normsum > consdata->capacity )
1032 {
1033 absviol = normsum - consdata->capacity;
1034 relviol = SCIPrelDiff(normsum, (SCIP_Real)consdata->capacity);
1035 }
1036 else
1037 {
1038 absviol = 0.0;
1039 relviol = 0.0;
1040 }
1041
1042 if( sol != NULL )
1043 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1044
1045 if( SCIPisFeasPositive(scip, absviol) )
1046 {
1047 *violated = TRUE;
1048
1049 /* only reset constraint age if we are in enforcement */
1050 if( sol == NULL )
1051 {
1053 }
1054
1055 if( printreason )
1056 {
1057 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1058
1059 SCIPinfoMessage(scip, NULL, ";\n");
1060 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1061 }
1062 }
1063 }
1064
1065 return SCIP_OKAY;
1066}
1067
1068/* IDX computes the integer index for the optimal solution array */
1069#define IDX(j,d) ((j)*(intcap)+(d))
1070
1071/** solves knapsack problem in maximization form exactly using dynamic programming;
1072 * if needed, one can provide arrays to store all selected items and all not selected items
1073 *
1074 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1075 *
1076 * @note the algorithm will first compute a greedy solution and terminate
1077 * if the greedy solution is proven to be optimal.
1078 * The dynamic programming algorithm runs with a time and space complexity
1079 * of O(nitems * capacity).
1080 *
1081 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1082 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1083 * to be checked whether they are faster and whether they can reconstruct the solution.
1084 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1085 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1086 * This could be implemented, however, it would be technically a bit cumbersome,
1087 * since one needs the greedy solution and the LP-value for this.
1088 * This is currently only available after the redundant items have already been sorted out.
1089 */
1091 SCIP* scip, /**< SCIP data structure */
1092 int nitems, /**< number of available items */
1093 SCIP_Longint* weights, /**< item weights */
1094 SCIP_Real* profits, /**< item profits */
1095 SCIP_Longint capacity, /**< capacity of knapsack */
1096 int* items, /**< item numbers */
1097 int* solitems, /**< array to store items in solution, or NULL */
1098 int* nonsolitems, /**< array to store items not in solution, or NULL */
1099 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1100 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1101 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1102 SCIP_Bool* success /**< pointer to store if an error occurred during solving
1103 * (normally a memory problem) */
1104 )
1105{
1106 SCIP_RETCODE retcode;
1107 SCIP_Real* tempsort;
1108 SCIP_Real* optvalues;
1109 int intcap;
1110 int d;
1111 int j;
1112 int greedymedianpos;
1113 SCIP_Longint weightsum;
1114 int* myitems;
1115 SCIP_Longint* myweights;
1116 SCIP_Real* realweights;
1117 int* allcurrminweight;
1118 SCIP_Real* myprofits;
1119 int nmyitems;
1120 SCIP_Longint gcd;
1121 SCIP_Longint minweight;
1122 SCIP_Longint maxweight;
1123 int currminweight;
1124 SCIP_Longint greedysolweight;
1125 SCIP_Real greedysolvalue;
1126 SCIP_Real greedyupperbound;
1127 SCIP_Bool eqweights;
1128 SCIP_Bool intprofits;
1129
1130 assert(weights != NULL);
1131 assert(profits != NULL);
1132 assert(capacity >= 0);
1133 assert(items != NULL);
1134 assert(nitems >= 0);
1135 assert(success != NULL);
1136
1137 *success = TRUE;
1138
1139#ifndef NDEBUG
1140 for( j = nitems - 1; j >= 0; --j )
1141 assert(weights[j] >= 0);
1142#endif
1143
1144 SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1145
1146 /* initializing solution value */
1147 if( solval != NULL )
1148 *solval = 0.0;
1149
1150 /* init solution information */
1151 if( solitems != NULL )
1152 {
1153 assert(items != NULL);
1154 assert(nsolitems != NULL);
1155 assert(nonsolitems != NULL);
1156 assert(nnonsolitems != NULL);
1157
1158 *nnonsolitems = 0;
1159 *nsolitems = 0;
1160 }
1161
1162 /* allocate temporary memory */
1163 SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1164 SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1165 SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1166 nmyitems = 0;
1167 weightsum = 0;
1168 minweight = SCIP_LONGINT_MAX;
1169 maxweight = 0;
1170
1171 /* remove unnecessary items */
1172 for( j = 0; j < nitems; ++j )
1173 {
1174 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1175
1176 /* item does not fit */
1177 if( weights[j] > capacity )
1178 {
1179 if( solitems != NULL )
1180 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1181 }
1182 /* item is not profitable */
1183 else if( profits[j] <= 0.0 )
1184 {
1185 if( solitems != NULL )
1186 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1187 }
1188 /* item always fits */
1189 else if( weights[j] == 0 )
1190 {
1191 if( solitems != NULL )
1192 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1193
1194 if( solval != NULL )
1195 *solval += profits[j];
1196 }
1197 /* all important items */
1198 else
1199 {
1200 myweights[nmyitems] = weights[j];
1201 myprofits[nmyitems] = profits[j];
1202 myitems[nmyitems] = items[j];
1203
1204 /* remember smallest item */
1205 if( myweights[nmyitems] < minweight )
1206 minweight = myweights[nmyitems];
1207
1208 /* remember bigest item */
1209 if( myweights[nmyitems] > maxweight )
1210 maxweight = myweights[nmyitems];
1211
1212 weightsum += myweights[nmyitems];
1213 ++nmyitems;
1214 }
1215 }
1216
1217 intprofits = TRUE;
1218 /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1219 for( j = 0; j < nmyitems && intprofits; ++j )
1220 intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1221
1222 /* if no item is left then goto end */
1223 if( nmyitems == 0 )
1224 {
1225 SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1226
1227 goto TERMINATE;
1228 }
1229
1230 /* if all items fit, we also do not need to do the expensive stuff later on */
1231 if( weightsum > 0 && weightsum <= capacity )
1232 {
1233 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1234
1235 for( j = nmyitems - 1; j >= 0; --j )
1236 {
1237 if( solitems != NULL )
1238 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1239
1240 if( solval != NULL )
1241 *solval += myprofits[j];
1242 }
1243
1244 goto TERMINATE;
1245 }
1246
1247 assert(0 < minweight && minweight <= capacity );
1248 assert(0 < maxweight && maxweight <= capacity);
1249
1250 /* make weights relatively prime */
1251 eqweights = TRUE;
1252 if( maxweight > 1 )
1253 {
1254 /* determine greatest common divisor */
1255 gcd = myweights[nmyitems - 1];
1256 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1257 gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1258
1259 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1260
1261 /* divide by greatest common divisor */
1262 if( gcd > 1 )
1263 {
1264 for( j = nmyitems - 1; j >= 0; --j )
1265 {
1266 myweights[j] /= gcd;
1267 eqweights = eqweights && (myweights[j] == 1);
1268 }
1269 capacity /= gcd;
1270 minweight /= gcd;
1271 }
1272 else
1273 eqweights = FALSE;
1274 }
1275 assert(minweight <= capacity);
1276
1277 /* if only one item fits, then take the best */
1278 if( minweight > capacity / 2 )
1279 {
1280 int p;
1281
1282 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1283
1284 p = nmyitems - 1;
1285
1286 /* find best item */
1287 for( j = nmyitems - 2; j >= 0; --j )
1288 {
1289 if( myprofits[j] > myprofits[p] )
1290 p = j;
1291 }
1292
1293 /* update solution information */
1294 if( solitems != NULL )
1295 {
1296 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1297
1298 solitems[(*nsolitems)++] = myitems[p];
1299 for( j = nmyitems - 1; j >= 0; --j )
1300 {
1301 if( j != p )
1302 nonsolitems[(*nnonsolitems)++] = myitems[j];
1303 }
1304 }
1305 /* update solution value */
1306 if( solval != NULL )
1307 *solval += myprofits[p];
1308
1309 goto TERMINATE;
1310 }
1311
1312 /* if all items have the same weight, then take the best */
1313 if( eqweights )
1314 {
1315 SCIP_Real addval = 0.0;
1316
1317 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1318
1319 SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1320
1321 /* update solution information */
1322 if( solitems != NULL || solval != NULL )
1323 {
1325
1326 /* if all items would fit we had handled this case before */
1327 assert((SCIP_Longint) nmyitems > capacity);
1328 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1329
1330 /* take the first best items into the solution */
1331 for( i = capacity - 1; i >= 0; --i )
1332 {
1333 if( solitems != NULL )
1334 solitems[(*nsolitems)++] = myitems[i];
1335 addval += myprofits[i];
1336 }
1337
1338 if( solitems != NULL )
1339 {
1340 /* the rest are not in the solution */
1341 for( i = nmyitems - 1; i >= capacity; --i )
1342 nonsolitems[(*nnonsolitems)++] = myitems[i];
1343 }
1344 }
1345 /* update solution value */
1346 if( solval != NULL )
1347 {
1348 assert(addval > 0.0);
1349 *solval += addval;
1350 }
1351
1352 goto TERMINATE;
1353 }
1354
1355 SCIPdebugMsg(scip, "Determine greedy solution.\n");
1356
1357 /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1358 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1359 */
1360 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1361 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1362
1363 for( j = 0; j < nmyitems; ++j )
1364 {
1365 tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1366 realweights[j] = (SCIP_Real)myweights[j];
1367 }
1368
1369 SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1370 (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1371
1372 SCIPfreeBufferArray(scip, &realweights);
1373 SCIPfreeBufferArray(scip, &tempsort);
1374
1375 /* initialize values for greedy solution information */
1376 greedysolweight = 0;
1377 greedysolvalue = 0.0;
1378
1379 /* determine greedy solution */
1380 for( j = 0; j < greedymedianpos; ++j )
1381 {
1382 assert(myweights[j] <= capacity);
1383
1384 /* update greedy solution weight and value */
1385 greedysolweight += myweights[j];
1386 greedysolvalue += myprofits[j];
1387 }
1388
1389 assert(0 < greedysolweight && greedysolweight <= capacity);
1390 assert(greedysolvalue > 0.0);
1391
1392 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1393 * - the greedy solution reaches the capacity, because then the LP solution is integral;
1394 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1395 greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1396 if( intprofits )
1397 greedyupperbound = SCIPfloor(scip, greedyupperbound);
1398 if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1399 {
1400 SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1401
1402 /* update solution information */
1403 if( solitems != NULL )
1404 {
1405 int l;
1406
1407 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1408
1409 /* collect items */
1410 for( l = 0; l < j; ++l )
1411 solitems[(*nsolitems)++] = myitems[l];
1412 for ( ; l < nmyitems; ++l )
1413 nonsolitems[(*nnonsolitems)++] = myitems[l];
1414 }
1415 /* update solution value */
1416 if( solval != NULL )
1417 {
1418 assert(greedysolvalue > 0.0);
1419 *solval += greedysolvalue;
1420 }
1421
1422 goto TERMINATE;
1423 }
1424
1425 /* in the following table we do not need the first minweight columns */
1426 capacity -= (minweight - 1);
1427
1428 /* we can only handle integers */
1429 if( capacity >= INT_MAX )
1430 {
1431 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1432
1433 *success = FALSE;
1434 goto TERMINATE;
1435 }
1436 assert(capacity < INT_MAX);
1437
1438 intcap = (int)capacity;
1439 assert(intcap >= 0);
1440 assert(nmyitems > 0);
1441 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1442
1443 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1444 * computing the size for the allocation
1445 */
1446 if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (SIZE_MAX / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1447 {
1448 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1449
1450 *success = FALSE;
1451 goto TERMINATE;
1452 }
1453
1454 /* allocate temporary memory and check for memory exceedance */
1455 retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1456 if( retcode == SCIP_NOMEMORY )
1457 {
1458 SCIPdebugMsg(scip, "Did not get enough memory.\n");
1459
1460 *success = FALSE;
1461 goto TERMINATE;
1462 }
1463 else
1464 {
1465 SCIP_CALL( retcode );
1466 }
1467
1468 SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1469
1470 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1471 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1472 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1473 * 'nmyitem' values
1474 */
1475 SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1476 assert(myweights[0] - minweight < INT_MAX);
1477 currminweight = (int) (myweights[0] - minweight);
1478 allcurrminweight[0] = currminweight;
1479
1480 /* fills first row of dynamic programming table with optimal values */
1481 for( d = currminweight; d < intcap; ++d )
1482 optvalues[d] = myprofits[0];
1483
1484 /* fills dynamic programming table with optimal values */
1485 for( j = 1; j < nmyitems; ++j )
1486 {
1487 int intweight;
1488
1489 /* compute important part of weight, which will be represented in the table */
1490 intweight = (int)(myweights[j] - minweight);
1491 assert(0 <= intweight && intweight < intcap);
1492
1493 /* copy all nonzeros from row above */
1494 for( d = currminweight; d < intweight && d < intcap; ++d )
1495 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1496
1497 /* update corresponding row */
1498 for( d = intweight; d < intcap; ++d )
1499 {
1500 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1501 if( d < currminweight )
1502 optvalues[IDX(j,d)] = myprofits[j];
1503 else
1504 {
1505 SCIP_Real sumprofit;
1506
1507 if( d - myweights[j] < currminweight )
1508 sumprofit = myprofits[j];
1509 else
1510 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1511
1512 optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1513 }
1514 }
1515
1516 /* update currminweight */
1517 if( intweight < currminweight )
1518 currminweight = intweight;
1519
1520 allcurrminweight[j] = currminweight;
1521 }
1522
1523 /* update optimal solution by following the table */
1524 if( solitems != NULL )
1525 {
1526 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1527 d = intcap - 1;
1528
1529 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1530
1531 /* insert all items in (non-) solution vector */
1532 for( j = nmyitems - 1; j > 0; --j )
1533 {
1534 /* if the following condition holds this means all remaining items does not fit anymore */
1535 if( d < allcurrminweight[j] )
1536 {
1537 /* we cannot have exceeded our capacity */
1538 assert((SCIP_Longint) d >= -minweight);
1539 break;
1540 }
1541
1542 /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1543 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1544 {
1545 solitems[(*nsolitems)++] = myitems[j];
1546
1547 /* check that we do not have an underflow */
1548 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1549 d = (int)(d - myweights[j]);
1550 }
1551 /* collect non-solution items */
1552 else
1553 nonsolitems[(*nnonsolitems)++] = myitems[j];
1554 }
1555
1556 /* insert remaining items */
1557 if( d >= allcurrminweight[j] )
1558 {
1559 assert(j == 0);
1560 solitems[(*nsolitems)++] = myitems[j];
1561 }
1562 else
1563 {
1564 assert(j >= 0);
1565 assert(d < allcurrminweight[j]);
1566
1567 for( ; j >= 0; --j )
1568 nonsolitems[(*nnonsolitems)++] = myitems[j];
1569 }
1570
1571 assert(*nsolitems + *nnonsolitems == nitems);
1572 }
1573
1574 /* update solution value */
1575 if( solval != NULL )
1576 *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1577 SCIPfreeBufferArray(scip, &allcurrminweight);
1578
1579 /* free all temporary memory */
1580 SCIPfreeBufferArray(scip, &optvalues);
1581
1582 TERMINATE:
1583 SCIPfreeBufferArray(scip, &myitems);
1584 SCIPfreeBufferArray(scip, &myprofits);
1585 SCIPfreeBufferArray(scip, &myweights);
1586
1587 return SCIP_OKAY;
1588}
1589
1590/** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1591 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1592 * selected items
1593 */
1595 SCIP* scip, /**< SCIP data structure */
1596 int nitems, /**< number of available items */
1597 SCIP_Longint* weights, /**< item weights */
1598 SCIP_Real* profits, /**< item profits */
1599 SCIP_Longint capacity, /**< capacity of knapsack */
1600 int* items, /**< item numbers */
1601 int* solitems, /**< array to store items in solution, or NULL */
1602 int* nonsolitems, /**< array to store items not in solution, or NULL */
1603 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1604 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1605 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1606 )
1607{
1608 SCIP_Real* tempsort;
1609 SCIP_Longint solitemsweight;
1610 SCIP_Real* realweights;
1611 int j;
1612 int criticalindex;
1613
1614 assert(weights != NULL);
1615 assert(profits != NULL);
1616 assert(capacity >= 0);
1617 assert(items != NULL);
1618 assert(nitems >= 0);
1619
1620 if( solitems != NULL )
1621 {
1622 *nsolitems = 0;
1623 *nnonsolitems = 0;
1624 }
1625 if( solval != NULL )
1626 *solval = 0.0;
1627
1628 /* initialize data for median search */
1629 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1630 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1631 for( j = nitems - 1; j >= 0; --j )
1632 {
1633 tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1634 realweights[j] = (SCIP_Real)weights[j];
1635 }
1636
1637 /* partially sort indices such that all elements that are larger than the break item appear first */
1638 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1639
1640 /* selects items as long as they fit into the knapsack */
1641 solitemsweight = 0;
1642 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1643 {
1644 if( solitems != NULL )
1645 solitems[(*nsolitems)++] = items[j];
1646
1647 if( solval != NULL )
1648 (*solval) += profits[j];
1649 solitemsweight += weights[j];
1650 }
1651 if ( solitems != NULL )
1652 {
1653 for( ; j < nitems; j++ )
1654 nonsolitems[(*nnonsolitems)++] = items[j];
1655 }
1656
1657 SCIPfreeBufferArray(scip, &realweights);
1658 SCIPfreeBufferArray(scip, &tempsort);
1659
1660 return SCIP_OKAY;
1661}
1662
1663#ifdef SCIP_DEBUG
1664/** prints all nontrivial GUB constraints and their LP solution values */
1665static
1666void GUBsetPrint(
1667 SCIP* scip, /**< SCIP data structure */
1668 SCIP_GUBSET* gubset, /**< GUB set data structure */
1669 SCIP_VAR** vars, /**< variables in knapsack constraint */
1670 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1671 )
1672{
1673 int nnontrivialgubconss;
1674 int c;
1675
1676 nnontrivialgubconss = 0;
1677
1678 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1679
1680 /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1681 for( c = 0; c < gubset->ngubconss; c++ )
1682 {
1683 SCIP_Real gubsolval;
1684
1685 assert(gubset->gubconss[c]->ngubvars >= 0);
1686
1687 /* nontrivial GUB */
1688 if( gubset->gubconss[c]->ngubvars > 1 )
1689 {
1690 int v;
1691
1692 gubsolval = 0.0;
1693 SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1694
1695 /* print GUB var */
1696 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1697 {
1698 int currentvar;
1699
1700 currentvar = gubset->gubconss[c]->gubvars[v];
1701 if( solvals != NULL )
1702 {
1703 gubsolval += solvals[currentvar];
1704 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1705 }
1706 else
1707 {
1708 SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1709 }
1710 }
1711
1712 /* check whether LP solution satisfies the GUB constraint */
1713 if( solvals != NULL )
1714 {
1715 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1716 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1717 }
1718 else
1719 {
1720 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1721 }
1722 nnontrivialgubconss++;
1723 }
1724 }
1725
1726 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1727}
1728#endif
1729
1730/** creates an empty GUB constraint */
1731static
1733 SCIP* scip, /**< SCIP data structure */
1734 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1735 )
1736{
1737 assert(scip != NULL);
1738 assert(gubcons != NULL);
1739
1740 /* allocate memory for GUB constraint data structures */
1741 SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1742 (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1743 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1744 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1745
1746 (*gubcons)->ngubvars = 0;
1747
1748 return SCIP_OKAY;
1749}
1750
1751/** frees GUB constraint */
1752static
1754 SCIP* scip, /**< SCIP data structure */
1755 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1756 )
1757{
1758 assert(scip != NULL);
1759 assert(gubcons != NULL);
1760 assert((*gubcons)->gubvars != NULL);
1761 assert((*gubcons)->gubvarsstatus != NULL);
1762
1763 /* free allocated memory */
1764 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1765 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1766 SCIPfreeBuffer(scip, gubcons);
1767}
1768
1769/** adds variable to given GUB constraint */
1770static
1772 SCIP* scip, /**< SCIP data structure */
1773 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1774 int var /**< index of given variable in knapsack constraint */
1775 )
1776{
1777 assert(scip != NULL);
1778 assert(gubcons != NULL);
1779 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1780 assert(gubcons->gubvars != NULL);
1781 assert(gubcons->gubvarsstatus != NULL);
1782 assert(var >= 0);
1783
1784 /* add variable to GUB constraint */
1785 gubcons->gubvars[gubcons->ngubvars] = var;
1786 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1787 gubcons->ngubvars++;
1788
1789 /* increase space allocated to GUB constraint if the number of variables reaches the size */
1790 if( gubcons->ngubvars == gubcons->gubvarssize )
1791 {
1792 int newlen;
1793
1794 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1795 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1796 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1797
1798 gubcons->gubvarssize = newlen;
1799 }
1800
1801 return SCIP_OKAY;
1802}
1803
1804/** deletes variable from its current GUB constraint */
1805static
1807 SCIP* scip, /**< SCIP data structure */
1808 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1809 int var, /**< index of given variable in knapsack constraint */
1810 int gubvarsidx /**< index of the variable in its current GUB constraint */
1811 )
1812{
1813 assert(scip != NULL);
1814 assert(gubcons != NULL);
1815 assert(var >= 0);
1816 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1817 assert(gubcons->ngubvars >= gubvarsidx+1);
1818 assert(gubcons->gubvars[gubvarsidx] == var);
1819
1820 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1821 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1822 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1823 gubcons->ngubvars--;
1824
1825 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1826 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1827 {
1828 int newlen;
1829
1830 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1831
1832 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1833 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1834
1835 gubcons->gubvarssize = newlen;
1836 }
1837
1838 return SCIP_OKAY;
1839}
1840
1841/** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1842static
1844 SCIP* scip, /**< SCIP data structure */
1845 SCIP_GUBSET* gubset, /**< GUB set data structure */
1846 SCIP_VAR** vars, /**< variables in knapsack constraint */
1847 int var, /**< index of given variable in knapsack constraint */
1848 int oldgubcons, /**< index of old GUB constraint of given variable */
1849 int newgubcons /**< index of new GUB constraint of given variable */
1850 )
1851{
1852 int oldgubvaridx;
1853 int replacevar;
1854 int j;
1855
1856 assert(scip != NULL);
1857 assert(gubset != NULL);
1858 assert(var >= 0);
1859 assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1860 assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1861 assert(oldgubcons != newgubcons);
1862 assert(gubset->gubconssidx[var] == oldgubcons);
1863 assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1864 assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1865
1866 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1867
1868 oldgubvaridx = gubset->gubvarsidx[var];
1869
1870 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1871 SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1872
1873 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1874 * replacement variable is given by old position of the deleted variable
1875 */
1876 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1877 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1878 gubset->gubvarsidx[replacevar] = oldgubvaridx;
1879
1880 /* add variable to the end of new GUB constraint */
1881 SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1882 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1883
1884 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1885 gubset->gubconssidx[var] = newgubcons;
1886 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1887
1888 /* delete old GUB constraint if it became empty */
1889 if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1890 {
1891 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1892#ifdef SCIP_DEBUG
1893 GUBsetPrint(scip, gubset, vars, NULL);
1894#endif
1895
1896 /* free old GUB constraint */
1897 GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1898
1899 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1900 if( oldgubcons != gubset->ngubconss-1 )
1901 {
1902 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1903 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1904
1905 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1906 * replacement GUB is given by old position of the deleted GUB
1907 */
1908 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1909 {
1910 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1911 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1912 }
1913 }
1914
1915 /* update number of GUB constraints */
1916 gubset->ngubconss--;
1917
1918 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1919 * (because it was at the end of the GUB constraint array)
1920 */
1921 assert(gubset->gubconssidx[var] == newgubcons
1922 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1923 }
1924#ifndef NDEBUG
1925 else
1926 assert(gubset->gubconssidx[var] == newgubcons);
1927#endif
1928
1929 return SCIP_OKAY;
1930}
1931
1932/** swaps two variables in the same GUB constraint */
1933static
1935 SCIP* scip, /**< SCIP data structure */
1936 SCIP_GUBSET* gubset, /**< GUB set data structure */
1937 int var1, /**< first variable to be swapped */
1938 int var2 /**< second variable to be swapped */
1939 )
1940{
1941 int gubcons;
1942 int var1idx;
1943 GUBVARSTATUS var1status;
1944 int var2idx;
1945 GUBVARSTATUS var2status;
1946
1947 assert(scip != NULL);
1948 assert(gubset != NULL);
1949
1950 gubcons = gubset->gubconssidx[var1];
1951 assert(gubcons == gubset->gubconssidx[var2]);
1952
1953 /* nothing to be done if both variables are the same */
1954 if( var1 == var2 )
1955 return;
1956
1957 /* swap index and status of variables in GUB constraint */
1958 var1idx = gubset->gubvarsidx[var1];
1959 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1960 var2idx = gubset->gubvarsidx[var2];
1961 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1962
1963 gubset->gubvarsidx[var1] = var2idx;
1964 gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1965 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1966
1967 gubset->gubvarsidx[var2] = var1idx;
1968 gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1969 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1970}
1971
1972/** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1973static
1975 SCIP* scip, /**< SCIP data structure */
1976 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1977 int nvars, /**< number of variables in the knapsack constraint */
1978 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1979 SCIP_Longint capacity /**< capacity of knapsack */
1980 )
1981{
1982 int i;
1983
1984 assert(scip != NULL);
1985 assert(gubset != NULL);
1986 assert(nvars > 0);
1987 assert(weights != NULL);
1988 assert(capacity >= 0);
1989
1990 /* allocate memory for GUB set data structures */
1991 SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1992 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1993 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1994 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1995 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1996 (*gubset)->ngubconss = nvars;
1997 (*gubset)->nvars = nvars;
1998
1999 /* initialize the set of GUB constraints */
2000 for( i = 0; i < nvars; i++ )
2001 {
2002 /* assign each variable to a new (trivial) GUB constraint */
2003 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2004 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2005
2006 /* set status of GUB constraint to initial */
2007 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2008
2009 (*gubset)->gubconssidx[i] = i;
2010 (*gubset)->gubvarsidx[i] = 0;
2011 assert((*gubset)->gubconss[i]->ngubvars == 1);
2012
2013 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2014 if( weights[i] > capacity )
2015 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2016 }
2017
2018 return SCIP_OKAY;
2019}
2020
2021/** frees GUB set data structure */
2022static
2024 SCIP* scip, /**< SCIP data structure */
2025 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2026 )
2027{
2028 int i;
2029
2030 assert(scip != NULL);
2031 assert(gubset != NULL);
2032 assert((*gubset)->gubconss != NULL);
2033 assert((*gubset)->gubconsstatus != NULL);
2034 assert((*gubset)->gubconssidx != NULL);
2035 assert((*gubset)->gubvarsidx != NULL);
2036
2037 /* free all GUB constraints */
2038 for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2039 {
2040 assert((*gubset)->gubconss[i] != NULL);
2041 GUBconsFree(scip, &(*gubset)->gubconss[i]);
2042 }
2043
2044 /* free allocated memory */
2045 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2046 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2047 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2048 SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2049 SCIPfreeBuffer(scip, gubset);
2050}
2051
2052#ifndef NDEBUG
2053/** checks whether GUB set data structure is consistent */
2054static
2056 SCIP* scip, /**< SCIP data structure */
2057 SCIP_GUBSET* gubset, /**< GUB set data structure */
2058 SCIP_VAR** vars /**< variables in the knapsack constraint */
2059 )
2060{
2061 int i;
2062 int gubconsidx;
2063 int gubvaridx;
2064 SCIP_VAR* var1;
2065 SCIP_VAR* var2;
2066 SCIP_Bool var1negated;
2067 SCIP_Bool var2negated;
2068
2069 assert(scip != NULL);
2070 assert(gubset != NULL);
2071
2072 SCIPdebugMsg(scip, " GUB set consistency check:\n");
2073
2074 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2075 for( i = 0; i < gubset->nvars; i++ )
2076 {
2077 gubconsidx = gubset->gubconssidx[i];
2078 gubvaridx = gubset->gubvarsidx[i];
2079
2080 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2081 {
2082 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2083 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2084 }
2085 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2086 }
2087
2088 /* checks for each GUB whether all pairs of its variables have a common clique */
2089 for( i = 0; i < gubset->ngubconss; i++ )
2090 {
2091 int j;
2092
2093 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2094 {
2095 int k;
2096
2097 /* get corresponding active problem variable */
2098 var1 = vars[gubset->gubconss[i]->gubvars[j]];
2099 var1negated = FALSE;
2100 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2101
2102 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2103 {
2104 /* get corresponding active problem variable */
2105 var2 = vars[gubset->gubconss[i]->gubvars[k]];
2106 var2negated = FALSE;
2107 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2108
2109 if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2110 {
2111 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2112 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2113 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2114 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2115 SCIPvarGetName(var1), k,
2116 SCIPvarGetName(var2));
2117 }
2118
2119 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2120 assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2121 }
2122 }
2123 }
2124 SCIPdebugMsg(scip, " --> successful\n");
2125
2126 return SCIP_OKAY;
2127}
2128#endif
2129
2130/** calculates a partition of the given set of binary variables into cliques;
2131 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2132 * were assigned to the same clique;
2133 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2134 * the preceding variables was assigned to clique i-1;
2135 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2136 * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2137 */
2138
2139static
2141 SCIP*const scip, /**< SCIP data structure */
2142 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2143 int const nvars, /**< number of variables in the clique */
2144 int*const cliquepartition, /**< array of length nvars to store the clique partition */
2145 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2146 SCIP_Real* solvals /**< solution values of all given binary variables */
2147 )
2148{
2149 SCIP_VAR** tmpvars;
2150 SCIP_VAR** cliquevars;
2151 SCIP_Bool* cliquevalues;
2152 SCIP_Bool* tmpvalues;
2153 int* varseq;
2154 int* sortkeys;
2155 int ncliquevars;
2156 int maxncliquevarscomp;
2157 int nignorevars;
2158 int nvarsused;
2159 int i;
2160
2161 assert(scip != NULL);
2162 assert(nvars == 0 || vars != NULL);
2163 assert(nvars == 0 || cliquepartition != NULL);
2164 assert(ncliques != NULL);
2165
2166 if( nvars == 0 )
2167 {
2168 *ncliques = 0;
2169 return SCIP_OKAY;
2170 }
2171
2172 /* allocate temporary memory for storing the variables of the current clique */
2173 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2174 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2175 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2178 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2179
2180 /* initialize the cliquepartition array with -1 */
2181 /* initialize the tmpvalues array */
2182 for( i = nvars - 1; i >= 0; --i )
2183 {
2184 tmpvalues[i] = TRUE;
2185 cliquepartition[i] = -1;
2186 }
2187
2188 /* get corresponding active problem variables */
2189 SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2190
2191 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2192 * by nondecreasing number of cliques the variables are in
2193 */
2194 nignorevars = 0;
2195 nvarsused = 0;
2196 for( i = 0; i < nvars; i++ )
2197 {
2198 if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2199 {
2200 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2201 varseq[nvars-1-nignorevars] = i;
2202 nignorevars++;
2203 }
2204 else
2205 {
2206 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2207 varseq[nvarsused] = i;
2208 sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2209 nvarsused++;
2210 }
2211 }
2212 assert(nvarsused + nignorevars == nvars);
2213
2214 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2215 SCIPsortIntInt(sortkeys, varseq, nvarsused);
2216
2217 maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2218
2219 /* calculate the clique partition */
2220 *ncliques = 0;
2221 for( i = 0; i < nvars; ++i )
2222 {
2223 if( cliquepartition[varseq[i]] == -1 )
2224 {
2225 int j;
2226
2227 /* variable starts a new clique */
2228 cliquepartition[varseq[i]] = *ncliques;
2229 cliquevars[0] = tmpvars[varseq[i]];
2230 cliquevalues[0] = tmpvalues[varseq[i]];
2231 ncliquevars = 1;
2232
2233 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2234 * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2235 */
2236 if( i < nvarsused && SCIPvarIsActive(tmpvars[varseq[i]]) )
2237 {
2238 /* greedily fill up the clique */
2239 for( j = i + 1; j < nvarsused; ++j )
2240 {
2241 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2242 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2243 {
2244 int k;
2245
2246 /* check if every variable in the actual clique is in clique with the new variable */
2247 for( k = ncliquevars - 1; k >= 0; --k )
2248 {
2249 if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2250 cliquevalues[k], TRUE) )
2251 break;
2252 }
2253
2254 if( k == -1 )
2255 {
2256 /* put the variable into the same clique */
2257 cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2258 cliquevars[ncliquevars] = tmpvars[varseq[j]];
2259 cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2260 ++ncliquevars;
2261 }
2262 }
2263 }
2264 }
2265
2266 /* this clique is finished */
2267 ++(*ncliques);
2268 }
2269 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2270
2271 /* break if we reached the maximal number of comparisons */
2272 if( i * nvars > maxncliquevarscomp )
2273 break;
2274 }
2275 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2276 for( ; i < nvars; ++i )
2277 {
2278 if( cliquepartition[varseq[i]] == -1 )
2279 {
2280 cliquepartition[varseq[i]] = *ncliques;
2281 ++(*ncliques);
2282 }
2283 }
2284
2285 /* free temporary memory */
2286 SCIPfreeBufferArray(scip, &sortkeys);
2287 SCIPfreeBufferArray(scip, &varseq);
2288 SCIPfreeBufferArray(scip, &tmpvars);
2289 SCIPfreeBufferArray(scip, &tmpvalues);
2290 SCIPfreeBufferArray(scip, &cliquevalues);
2291 SCIPfreeBufferArray(scip, &cliquevars);
2292
2293 return SCIP_OKAY;
2294}
2295
2296/** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2297static
2299 SCIP* scip, /**< SCIP data structure */
2300 SCIP_GUBSET* gubset, /**< GUB set data structure */
2301 SCIP_VAR** vars, /**< variables in the knapsack constraint */
2302 SCIP_Real* solvals /**< solution values of all knapsack variables */
2303 )
2304{
2305 int* cliquepartition;
2306 int* gubfirstvar;
2307 int ncliques;
2308 int currentgubconsidx;
2309 int newgubconsidx;
2310 int cliqueidx;
2311 int nvars;
2312 int i;
2313
2314 assert(scip != NULL);
2315 assert(gubset != NULL);
2316 assert(vars != NULL);
2317
2318 nvars = gubset->nvars;
2319 assert(nvars >= 0);
2320
2321 /* allocate temporary memory for clique partition */
2322 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2323
2324 /* compute sophisticated clique partition */
2325 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2326
2327 /* allocate temporary memory for GUB set data structure */
2328 SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2329
2330 /* translate GUB partition into GUB set data structure */
2331 for( i = 0; i < ncliques; i++ )
2332 {
2333 /* initialize first variable for every GUB */
2334 gubfirstvar[i] = -1;
2335 }
2336 /* move every knapsack variable into GUB defined by clique partition */
2337 for( i = 0; i < nvars; i++ )
2338 {
2339 assert(cliquepartition[i] >= 0);
2340
2341 cliqueidx = cliquepartition[i];
2342 currentgubconsidx = gubset->gubconssidx[i];
2343 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2344
2345 /* variable is first element in GUB constraint defined by clique partition */
2346 if( gubfirstvar[cliqueidx] == -1 )
2347 {
2348 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2349 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2350 */
2351 assert(gubset->gubvarsidx[i] == 0);
2352 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2353
2354 /* remember the first variable found for the current GUB */
2355 gubfirstvar[cliqueidx] = i;
2356 }
2357 /* variable is additional element of GUB constraint defined by clique partition */
2358 else
2359 {
2360 assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2361
2362 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2363 * first variable of this GUB constraint
2364 */
2365 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2366 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2367 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2368
2369 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2370 }
2371 }
2372
2373#ifdef SCIP_DEBUG
2374 /* prints GUB set data structure */
2375 GUBsetPrint(scip, gubset, vars, solvals);
2376#endif
2377
2378#ifndef NDEBUG
2379 /* checks consistency of GUB set data structure */
2380 SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2381#endif
2382
2383 /* free temporary memory */
2384 SCIPfreeBufferArray(scip, &gubfirstvar);
2385 SCIPfreeBufferArray(scip, &cliquepartition);
2386
2387 return SCIP_OKAY;
2388}
2389
2390/** gets a most violated cover C (\f$\sum_{j \in C} a_j > a_0\f$) for a given knapsack constraint \f$\sum_{j \in N} a_j x_j \leq a_0\f$
2391 * taking into consideration the following fixing: \f$j \in C\f$, if \f$j \in N_1 = \{j \in N : x^*_j = 1\}\f$ and
2392 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2393 */
2394static
2396 SCIP* scip, /**< SCIP data structure */
2397 SCIP_VAR** vars, /**< variables in knapsack constraint */
2398 int nvars, /**< number of variables in knapsack constraint */
2399 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2400 SCIP_Longint capacity, /**< capacity of knapsack */
2401 SCIP_Real* solvals, /**< solution values of all problem variables */
2402 int* covervars, /**< pointer to store cover variables */
2403 int* noncovervars, /**< pointer to store noncover variables */
2404 int* ncovervars, /**< pointer to store number of cover variables */
2405 int* nnoncovervars, /**< pointer to store number of noncover variables */
2406 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2407 SCIP_Bool* found, /**< pointer to store whether a cover was found */
2408 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2409 int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2410 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2411 )
2412{
2413 SCIP_Longint* transweights;
2414 SCIP_Real* transprofits;
2415 SCIP_Longint transcapacity;
2416 SCIP_Longint fixedonesweight;
2417 SCIP_Longint itemsweight;
2418 SCIP_Bool infeasible;
2419 int* fixedones;
2420 int* fixedzeros;
2421 int* items;
2422 int nfixedones;
2423 int nfixedzeros;
2424 int nitems;
2425 int j;
2426
2427 assert(scip != NULL);
2428 assert(vars != NULL);
2429 assert(nvars > 0);
2430 assert(weights != NULL);
2431 assert(capacity >= 0);
2432 assert(solvals != NULL);
2433 assert(covervars != NULL);
2434 assert(noncovervars != NULL);
2435 assert(ncovervars != NULL);
2436 assert(nnoncovervars != NULL);
2437 assert(coverweight != NULL);
2438 assert(found != NULL);
2439 assert(ntightened != NULL);
2440 assert(fractional != NULL);
2441
2442 SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2443
2444 /* allocates temporary memory */
2445 SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2446 SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2447 SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2448 SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2450
2451 *found = FALSE;
2452 *ncovervars = 0;
2453 *nnoncovervars = 0;
2454 *coverweight = 0;
2455 *fractional = TRUE;
2456
2457 /* gets the following sets
2458 * N_1 = {j in N : x*_j = 1} (fixedones),
2459 * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2460 * N\‍(N_0 & N_1) (items),
2461 * where x*_j is the solution value of variable x_j
2462 */
2463 nfixedones = 0;
2464 nfixedzeros = 0;
2465 nitems = 0;
2466 fixedonesweight = 0;
2467 itemsweight = 0;
2468 *ntightened = 0;
2469 for( j = 0; j < nvars; j++ )
2470 {
2472
2473 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2474 if( weights[j] > capacity )
2475 {
2476 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2477 assert(!infeasible);
2478 (*ntightened)++;
2479 continue;
2480 }
2481
2482 /* variable x_j has solution value one */
2483 if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2484 {
2485 fixedones[nfixedones] = j;
2486 nfixedones++;
2487 fixedonesweight += weights[j];
2488 }
2489 /* variable x_j has solution value zero */
2490 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2491 {
2492 fixedzeros[nfixedzeros] = j;
2493 nfixedzeros++;
2494 }
2495 /* variable x_j has fractional solution value */
2496 else
2497 {
2498 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2499 items[nitems] = j;
2500 nitems++;
2501 itemsweight += weights[j];
2502 }
2503 }
2504 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2505
2506 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2507 * the separation routine
2508 */
2509 assert(nitems >= 0);
2510 if( nitems == 0 )
2511 {
2512 *fractional = FALSE;
2513 goto TERMINATE;
2514 }
2515 assert(*fractional);
2516
2517 /* transforms the traditional separation problem (under consideration of the following fixing:
2518 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2519 *
2520 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2521 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2522 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2523 *
2524 * to a knapsack problem in maximization form by complementing the variables
2525 *
2526 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) -
2527 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2528 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2529 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2530 */
2531
2532 /* gets weight and profit of variables in transformed knapsack problem */
2533 for( j = 0; j < nitems; j++ )
2534 {
2535 transweights[j] = weights[items[j]];
2536 transprofits[j] = 1.0 - solvals[items[j]];
2537 }
2538 /* gets capacity of transformed knapsack problem */
2539 transcapacity = fixedonesweight + itemsweight - capacity - 1;
2540
2541 /* if capacity of transformed knapsack problem is less than zero, there is no cover
2542 * (when variables fixed to zero are not used)
2543 */
2544 if( transcapacity < 0 )
2545 {
2546 assert(!(*found));
2547 goto TERMINATE;
2548 }
2549
2550 if( modtransused )
2551 {
2552 /* transforms the modified separation problem (under consideration of the following fixing:
2553 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2554 *
2555 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2556 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2557 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2558 *
2559 * to a knapsack problem in maximization form by complementing the variables
2560 *
2561 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j -
2562 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2563 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2564 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2565 */
2566
2567 /* gets weight and profit of variables in modified transformed knapsack problem */
2568 for( j = 0; j < nitems; j++ )
2569 {
2570 transprofits[j] *= weights[items[j]];
2571 assert(SCIPisFeasPositive(scip, transprofits[j]));
2572 }
2573 }
2574
2575 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2576 * transformed knapsack problem using Dantzig's method and rounding down the solution.
2577 * let z* be the solution, then
2578 * j in C, if z*_j = 0 and
2579 * i in N\C, if z*_j = 1.
2580 */
2581 SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2582 noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2583 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2584
2585 /* constructs cover C (sum_{j in C} a_j > a_0) */
2586 for( j = 0; j < *ncovervars; j++ )
2587 {
2588 (*coverweight) += weights[covervars[j]];
2589 }
2590
2591 /* adds all variables from N_1 to C */
2592 for( j = 0; j < nfixedones; j++ )
2593 {
2594 covervars[*ncovervars] = fixedones[j];
2595 (*ncovervars)++;
2596 (*coverweight) += weights[fixedones[j]];
2597 }
2598
2599 /* adds all variables from N_0 to N\C */
2600 for( j = 0; j < nfixedzeros; j++ )
2601 {
2602 noncovervars[*nnoncovervars] = fixedzeros[j];
2603 (*nnoncovervars)++;
2604 }
2605 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2606 assert((*coverweight) > capacity);
2607 *found = TRUE;
2608
2609 TERMINATE:
2610 /* frees temporary memory */
2611 SCIPfreeBufferArray(scip, &items);
2612 SCIPfreeBufferArray(scip, &fixedzeros);
2613 SCIPfreeBufferArray(scip, &fixedones);
2614 SCIPfreeBufferArray(scip, &transprofits);
2615 SCIPfreeBufferArray(scip, &transweights);
2616
2617 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2618
2619 return SCIP_OKAY;
2620}
2621
2622#ifndef NDEBUG
2623/** checks if minweightidx is set correctly
2624 */
2625static
2627 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2628 SCIP_Longint capacity, /**< capacity of knapsack */
2629 int* covervars, /**< pointer to store cover variables */
2630 int ncovervars, /**< pointer to store number of cover variables */
2631 SCIP_Longint coverweight, /**< pointer to store weight of cover */
2632 int minweightidx, /**< index of variable in cover variables with minimum weight */
2633 int j /**< current index in cover variables */
2634 )
2635{
2636 SCIP_Longint minweight;
2637 int i;
2638
2639 assert(weights != NULL);
2640 assert(covervars != NULL);
2641 assert(ncovervars > 0);
2642
2643 minweight = weights[covervars[minweightidx]];
2644
2645 /* checks if all cover variables before index j have weight greater than minweight */
2646 for( i = 0; i < j; i++ )
2647 {
2648 assert(weights[covervars[i]] > minweight);
2649 if( weights[covervars[i]] <= minweight )
2650 return FALSE;
2651 }
2652
2653 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2654 for( i = 0; i < j; i++ )
2655 {
2656 assert(coverweight - weights[covervars[i]] <= capacity);
2657 if( coverweight - weights[covervars[i]] > capacity )
2658 return FALSE;
2659 }
2660 return TRUE;
2661}
2662#endif
2663
2664
2665/** gets partition \f$(C_1,C_2)\f$ of minimal cover \f$C\f$, i.e. \f$C_1 \cup C_2 = C\f$ and \f$C_1 \cap C_2 = \emptyset\f$,
2666 * with \f$C_1\f$ not empty; chooses partition as follows \f$C_2 = \{ j \in C : x^*_j = 1 \}\f$ and \f$C_1 = C \setminus C_2\f$
2667 */
2668static
2670 SCIP* scip, /**< SCIP data structure */
2671 SCIP_Real* solvals, /**< solution values of all problem variables */
2672 int* covervars, /**< cover variables */
2673 int ncovervars, /**< number of cover variables */
2674 int* varsC1, /**< pointer to store variables in C1 */
2675 int* varsC2, /**< pointer to store variables in C2 */
2676 int* nvarsC1, /**< pointer to store number of variables in C1 */
2677 int* nvarsC2 /**< pointer to store number of variables in C2 */
2678 )
2679{
2680 int j;
2681
2682 assert(scip != NULL);
2683 assert(ncovervars >= 0);
2684 assert(solvals != NULL);
2685 assert(covervars != NULL);
2686 assert(varsC1 != NULL);
2687 assert(varsC2 != NULL);
2688 assert(nvarsC1 != NULL);
2689 assert(nvarsC2 != NULL);
2690
2691 *nvarsC1 = 0;
2692 *nvarsC2 = 0;
2693 for( j = 0; j < ncovervars; j++ )
2694 {
2695 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2696
2697 /* variable has solution value one */
2698 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2699 {
2700 varsC2[*nvarsC2] = covervars[j];
2701 (*nvarsC2)++;
2702 }
2703 /* variable has solution value less than one */
2704 else
2705 {
2706 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2707 varsC1[*nvarsC1] = covervars[j];
2708 (*nvarsC1)++;
2709 }
2710 }
2711 assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2712}
2713
2714/** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2715 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2716 */
2717static
2719 SCIP* scip, /**< SCIP data structure */
2720 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2721 int* varsC1, /**< pointer to store variables in C1 */
2722 int* varsC2, /**< pointer to store variables in C2 */
2723 int* nvarsC1, /**< pointer to store number of variables in C1 */
2724 int* nvarsC2 /**< pointer to store number of variables in C2 */
2725 )
2726{
2727 SCIP_Real* sortkeysC2;
2728 int j;
2729
2730 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2731 assert(*nvarsC2 > 0);
2732
2733 /* allocates temporary memory */
2734 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2735
2736 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2737 for( j = 0; j < *nvarsC2; j++ )
2738 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2739 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2740
2741 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2742 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2743 while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2744 {
2745 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2746 (*nvarsC1)++;
2747 (*nvarsC2)--;
2748 }
2749
2750 /* frees temporary memory */
2751 SCIPfreeBufferArray(scip, &sortkeysC2);
2752
2753 return SCIP_OKAY;
2754}
2755
2756/** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2757static
2759 SCIP* scip, /**< SCIP data structure */
2760 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2761 int* varsC1, /**< pointer to store variables in C1 */
2762 int* varsC2, /**< pointer to store variables in C2 */
2763 int* nvarsC1, /**< pointer to store number of variables in C1 */
2764 int* nvarsC2 /**< pointer to store number of variables in C2 */
2765 )
2766{
2767 SCIP_Real* sortkeysC2;
2768 int j;
2769
2770 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2771 assert(*nvarsC2 > 0);
2772
2773 /* allocates temporary memory */
2774 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2775
2776 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2777 for( j = 0; j < *nvarsC2; j++ )
2778 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2779 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2780
2781 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2782 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2783 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2784 (*nvarsC1)++;
2785 (*nvarsC2)--;
2786
2787 /* frees temporary memory */
2788 SCIPfreeBufferArray(scip, &sortkeysC2);
2789
2790 return SCIP_OKAY;
2791}
2792
2793
2794/** gets partition \f$(F,R)\f$ of \f$N \setminus C\f$ where \f$C\f$ is a minimal cover, i.e. \f$F \cup R = N \setminus C\f$
2795 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2796 * \f$F = (N \setminus C) \setminus F\f$
2797 */
2798static
2800 SCIP* scip, /**< SCIP data structure */
2801 SCIP_Real* solvals, /**< solution values of all problem variables */
2802 int* noncovervars, /**< noncover variables */
2803 int nnoncovervars, /**< number of noncover variables */
2804 int* varsF, /**< pointer to store variables in F */
2805 int* varsR, /**< pointer to store variables in R */
2806 int* nvarsF, /**< pointer to store number of variables in F */
2807 int* nvarsR /**< pointer to store number of variables in R */
2808 )
2809{
2810 int j;
2811
2812 assert(scip != NULL);
2813 assert(nnoncovervars >= 0);
2814 assert(solvals != NULL);
2815 assert(noncovervars != NULL);
2816 assert(varsF != NULL);
2817 assert(varsR != NULL);
2818 assert(nvarsF != NULL);
2819 assert(nvarsR != NULL);
2820
2821 *nvarsF = 0;
2822 *nvarsR = 0;
2823
2824 for( j = 0; j < nnoncovervars; j++ )
2825 {
2826 /* variable has solution value zero */
2827 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2828 {
2829 varsR[*nvarsR] = noncovervars[j];
2830 (*nvarsR)++;
2831 }
2832 /* variable has solution value greater than zero */
2833 else
2834 {
2835 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2836 varsF[*nvarsF] = noncovervars[j];
2837 (*nvarsF)++;
2838 }
2839 }
2840 assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2841}
2842
2843/** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2844 * lifting procedure
2845 */
2846static
2848 SCIP* scip, /**< SCIP data structure */
2849 SCIP_Real* solvals, /**< solution values of all problem variables */
2850 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2851 int* varsF, /**< pointer to store variables in F */
2852 int* varsC2, /**< pointer to store variables in C2 */
2853 int* varsR, /**< pointer to store variables in R */
2854 int nvarsF, /**< number of variables in F */
2855 int nvarsC2, /**< number of variables in C2 */
2856 int nvarsR /**< number of variables in R */
2857 )
2858{
2859 SORTKEYPAIR** sortkeypairsF;
2860 SORTKEYPAIR* sortkeypairsFstore;
2861 SCIP_Real* sortkeysC2;
2862 SCIP_Real* sortkeysR;
2863 int j;
2864
2865 assert(scip != NULL);
2866 assert(solvals != NULL);
2867 assert(weights != NULL);
2868 assert(varsF != NULL);
2869 assert(varsC2 != NULL);
2870 assert(varsR != NULL);
2871 assert(nvarsF >= 0);
2872 assert(nvarsC2 >= 0);
2873 assert(nvarsR >= 0);
2874
2875 /* allocates temporary memory */
2876 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2877 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2878 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2879 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2880
2881 /* gets sorting key for variables in F corresponding to the following lifting sequence
2882 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2883 * x*_1 >= x*_2 >= ... >= x*_|F|
2884 * in case of equality uses
2885 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2886 */
2887 for( j = 0; j < nvarsF; j++ )
2888 {
2889 sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2890 sortkeypairsF[j]->key1 = solvals[varsF[j]];
2891 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2892 }
2893
2894 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2895 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2896 */
2897 for( j = 0; j < nvarsC2; j++ )
2898 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2899
2900 /* gets sorting key for variables in R corresponding to the following lifting sequence
2901 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2902 */
2903 for( j = 0; j < nvarsR; j++ )
2904 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2905
2906 /* sorts F, C2 and R */
2907 if( nvarsF > 0 )
2908 {
2909 SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2910 }
2911 if( nvarsC2 > 0 )
2912 {
2913 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2914 }
2915 if( nvarsR > 0)
2916 {
2917 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2918 }
2919
2920 /* frees temporary memory */
2921 SCIPfreeBufferArray(scip, &sortkeysR);
2922 SCIPfreeBufferArray(scip, &sortkeysC2);
2923 SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2924 SCIPfreeBufferArray(scip, &sortkeypairsF);
2925
2926 return SCIP_OKAY;
2927}
2928
2929/** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2930 * for the sequential GUB wise lifting procedure
2931 */
2932static
2934 SCIP* scip, /**< SCIP data structure */
2935 SCIP_GUBSET* gubset, /**< GUB set data structure */
2936 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2937 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2938 int* varsC1, /**< variables in C1 */
2939 int* varsC2, /**< variables in C2 */
2940 int* varsF, /**< variables in F */
2941 int* varsR, /**< variables in R */
2942 int nvarsC1, /**< number of variables in C1 */
2943 int nvarsC2, /**< number of variables in C2 */
2944 int nvarsF, /**< number of variables in F */
2945 int nvarsR, /**< number of variables in R */
2946 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2947 int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2948 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2949 int* gubconsGR, /**< pointer to store GUBs in GR */
2950 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2951 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2952 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2953 int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2954 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2955 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2956 )
2957{
2958 SORTKEYPAIR** sortkeypairsGFC1;
2959 SORTKEYPAIR* sortkeypairsGFC1store;
2960 SCIP_Real* sortkeysC1;
2961 SCIP_Real* sortkeysC2;
2962 SCIP_Real* sortkeysR;
2963 int* nC1varsingubcons;
2964 int var;
2965 int gubconsidx;
2966 int varidx;
2967 int ngubconss;
2968 int ngubconsGOC1;
2969 int targetvar;
2970#ifndef NDEBUG
2971 int nvarsprocessed = 0;
2972#endif
2973 int i;
2974 int j;
2975
2976#if GUBSPLITGNC1GUBS
2977 SCIP_Bool gubconswithF;
2978 int origngubconss;
2979 origngubconss = gubset->ngubconss;
2980#endif
2981
2982 assert(scip != NULL);
2983 assert(gubset != NULL);
2984 assert(solvals != NULL);
2985 assert(weights != NULL);
2986 assert(varsC1 != NULL);
2987 assert(varsC2 != NULL);
2988 assert(varsF != NULL);
2989 assert(varsR != NULL);
2990 assert(nvarsC1 > 0);
2991 assert(nvarsC2 >= 0);
2992 assert(nvarsF >= 0);
2993 assert(nvarsR >= 0);
2994 assert(gubconsGC1 != NULL);
2995 assert(gubconsGC2 != NULL);
2996 assert(gubconsGFC1 != NULL);
2997 assert(gubconsGR != NULL);
2998 assert(ngubconsGC1 != NULL);
2999 assert(ngubconsGC2 != NULL);
3000 assert(ngubconsGFC1 != NULL);
3001 assert(ngubconsGR != NULL);
3002 assert(maxgubvarssize != NULL);
3003
3004 ngubconss = gubset->ngubconss;
3005 ngubconsGOC1 = 0;
3006
3007 /* GUBs are categorized into different types according to the variables in volved
3008 * - GOC1: involves variables in C1 only -- no C2, R, F
3009 * - GNC1: involves variables in C1 and F (and R) -- no C2
3010 * - GF: involves variables in F (and R) only -- no C1, C2
3011 * - GC2: involves variables in C2 only -- no C1, R, F
3012 * - GR: involves variables in R only -- no C1, C2, F
3013 * which requires splitting GUBs in case they include variable in F and R.
3014 *
3015 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3016 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3017 * - second ordering level is
3018 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3019 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3020 * GR: non-increasing max{ a_k : k in GR_j}
3021 *
3022 * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3023 * - GC1: GUBs of category GOC1 and GNC1
3024 * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3025 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3026 */
3027
3028 /* allocates temporary memory */
3029 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3030 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3031 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3032
3033 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3034 * - F: non-increasing x*_j and non-increasing a_j in case of equality
3035 * - C2: non-increasing a_j
3036 * - R: non-increasing a_j
3037 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3038 */
3039
3040 /* gets sorting key for variables in C1 corresponding to the following ordering
3041 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3042 */
3043 for( j = 0; j < nvarsC1; j++ )
3044 {
3045 /* gets sortkeys */
3046 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3047
3048 /* update status of variable in its gub constraint */
3049 gubconsidx = gubset->gubconssidx[varsC1[j]];
3050 varidx = gubset->gubvarsidx[varsC1[j]];
3052 }
3053
3054 /* gets sorting key for variables in F corresponding to the following ordering
3055 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3056 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3057 * and updates status of each variable in F in GUB set data structure
3058 */
3059 for( j = 0; j < nvarsF; j++ )
3060 {
3061 /* update status of variable in its gub constraint */
3062 gubconsidx = gubset->gubconssidx[varsF[j]];
3063 varidx = gubset->gubvarsidx[varsF[j]];
3065 }
3066
3067 /* gets sorting key for variables in C2 corresponding to the following ordering
3068 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3069 * and updates status of each variable in F in GUB set data structure
3070 */
3071 for( j = 0; j < nvarsC2; j++ )
3072 {
3073 /* gets sortkeys */
3074 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3075
3076 /* update status of variable in its gub constraint */
3077 gubconsidx = gubset->gubconssidx[varsC2[j]];
3078 varidx = gubset->gubvarsidx[varsC2[j]];
3080 }
3081
3082 /* gets sorting key for variables in R corresponding to the following ordering
3083 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3084 * and updates status of each variable in F in GUB set data structure
3085 */
3086 for( j = 0; j < nvarsR; j++ )
3087 {
3088 /* gets sortkeys */
3089 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3090
3091 /* update status of variable in its gub constraint */
3092 gubconsidx = gubset->gubconssidx[varsR[j]];
3093 varidx = gubset->gubvarsidx[varsR[j]];
3095 }
3096
3097 /* sorts C1, F, C2 and R */
3098 assert(nvarsC1 > 0);
3099 SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3100
3101 if( nvarsC2 > 0 )
3102 {
3103 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3104 }
3105 if( nvarsR > 0)
3106 {
3107 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3108 }
3109
3110 /* frees temporary memory */
3111 SCIPfreeBufferArray(scip, &sortkeysR);
3112 SCIPfreeBufferArray(scip, &sortkeysC2);
3113 SCIPfreeBufferArray(scip, &sortkeysC1);
3114
3115 /* allocate and initialize temporary memory for sorting GUB constraints */
3116 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3117 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3118 SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3119 BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3120 for( i = 0; i < ngubconss; i++)
3121 {
3122 sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3123 sortkeypairsGFC1[i]->key1 = 0.0;
3124 sortkeypairsGFC1[i]->key2 = 0.0;
3125 }
3126 *ngubconsGC1 = 0;
3127 *ngubconsGC2 = 0;
3128 *ngubconsGFC1 = 0;
3129 *ngubconsGR = 0;
3130 *ngubconscapexceed = 0;
3131 *maxgubvarssize = 0;
3132
3133#ifndef NDEBUG
3134 for( i = 0; i < gubset->ngubconss; i++ )
3136#endif
3137
3138 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3139 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3140 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3141 * non-increasing number of variables in F, and
3142 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3143 */
3144 for( i = 0; i < nvarsC1; i++ )
3145 {
3146 int nvarsC1capexceed;
3147
3148 nvarsC1capexceed = 0;
3149
3150 var = varsC1[i];
3151 gubconsidx = gubset->gubconssidx[var];
3152 varidx = gubset->gubvarsidx[var];
3153
3154 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3156
3157 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3158 * note that variables in C1 are already sorted by non-decreasing weigth
3159 */
3160 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3161 GUBsetSwapVars(scip, gubset, var, targetvar);
3162 nC1varsingubcons[gubconsidx]++;
3163
3164 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3165 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3166 {
3168 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3169 continue;
3170 }
3171
3172 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3173 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3174 */
3175#if GUBSPLITGNC1GUBS
3176 gubconswithF = FALSE;
3177#endif
3178 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3179 {
3180 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3181
3182 /* C1-variable: update number of C1/capacity exceeding variables */
3183 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3184 {
3185 nvarsC1capexceed++;
3186#ifndef NDEBUG
3187 nvarsprocessed++;
3188#endif
3189 }
3190 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3191 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3192 {
3193#if GUBSPLITGNC1GUBS
3194 gubconswithF = TRUE;
3195#endif
3196 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3197
3198 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3199 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3200 }
3201 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3202 {
3203 nvarsC1capexceed++;
3204 }
3205 else
3206 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3207 }
3208
3209 /* update set of GC1 GUBs */
3210 gubconsGC1[*ngubconsGC1] = gubconsidx;
3211 (*ngubconsGC1)++;
3212
3213 /* update maximum size of all GUB constraints */
3214 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3215 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3216
3217 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3218 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3219 {
3220 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3221 ngubconsGOC1++;
3222 }
3223 else
3224 {
3225#if GUBSPLITGNC1GUBS
3226 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3227 if( !gubconswithF )
3228 {
3229 GUBVARSTATUS movevarstatus;
3230
3231 assert(gubset->ngubconss < gubset->nvars);
3232
3233 /* create a new GUB for GR part of splitting */
3234 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3235 gubset->ngubconss++;
3236 ngubconss = gubset->ngubconss;
3237
3238 /* fill GR with R variables in current GUB */
3239 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3240 {
3241 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3242 if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3243 {
3244 assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3245 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3246 gubconsidx, ngubconss-1) );
3247 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3248 movevarstatus;
3249 }
3250 }
3251
3252 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3253 ngubconsGOC1++;
3254
3256 gubconsGR[*ngubconsGR] = ngubconss-1;
3257 (*ngubconsGR)++;
3258 }
3259 /* variables in C1, F, and maybe R: GNC1 GUB */
3260 else
3261 {
3262 assert(gubconswithF);
3263
3264 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3265 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3266 (*ngubconsGFC1)++;
3267 }
3268#else
3269 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3270 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3271 (*ngubconsGFC1)++;
3272#endif
3273 }
3274 }
3275
3276 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3277 * are already sorted correctly
3278 */
3279 for( i = 0; i < nvarsC2; i++ )
3280 {
3281 var = varsC2[i];
3282 gubconsidx = gubset->gubconssidx[var];
3283 varidx = gubset->gubvarsidx[var];
3284
3285 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3286 assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3287 assert(varidx == 0);
3289 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3290
3291 /* set status of GC2 GUB */
3292 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3293
3294 /* update group of GC2 GUBs */
3295 gubconsGC2[*ngubconsGC2] = gubconsidx;
3296 (*ngubconsGC2)++;
3297
3298 /* update maximum size of all GUB constraints */
3299 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3300 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3301
3302#ifndef NDEBUG
3303 nvarsprocessed++;
3304#endif
3305 }
3306
3307 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3308 * non-increasing number of variables in F, and
3309 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3310 */
3311 for( i = 0; i < nvarsF; i++ )
3312 {
3313 var = varsF[i];
3314 gubconsidx = gubset->gubconssidx[var];
3315 varidx = gubset->gubvarsidx[var];
3316
3317 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3319
3320#ifndef NDEBUG
3321 nvarsprocessed++;
3322#endif
3323
3324 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3325 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3326 {
3328 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3329 continue;
3330 }
3331
3332 /* set status of GF GUB */
3333 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3334
3335 /* update sorting key of corresponding GFC1 GUB */
3336 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3337 {
3339 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3340
3341 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3342 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3343 {
3344 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3345
3346 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3347 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3348 }
3349 }
3350
3351 /* update set of GFC1 GUBs */
3352 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3353 (*ngubconsGFC1)++;
3354
3355 /* update maximum size of all GUB constraints */
3356 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3357 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3358 }
3359
3360 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3361 * correctly
3362 */
3363 for( i = 0; i < nvarsR; i++ )
3364 {
3365 var = varsR[i];
3366 gubconsidx = gubset->gubconssidx[var];
3367 varidx = gubset->gubvarsidx[var];
3368
3369 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3371
3372#ifndef NDEBUG
3373 nvarsprocessed++;
3374#endif
3375
3376 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3377 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3378 {
3380 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3381 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3382 continue;
3383 }
3384
3385 /* set status of GR GUB */
3386 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3387
3388 /* update set of GR GUBs */
3389 gubconsGR[*ngubconsGR] = gubconsidx;
3390 (*ngubconsGR)++;
3391
3392 /* update maximum size of all GUB constraints */
3393 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3394 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3395 }
3396 assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3397
3398 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3399 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3400 assert(*ngubconscapexceed >= 0);
3401#ifndef NDEBUG
3402 {
3403 int check;
3404
3405 check = 0;
3406
3407 /* remaining not handled GUBs should only contain capacity exceeding variables */
3408 for( i = 0; i < ngubconss; i++ )
3409 {
3410 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3411 check++;
3412 }
3413 assert(check == *ngubconscapexceed);
3414 }
3415#endif
3416
3417 /* sort GFCI GUBs according to computed sorting keys */
3418 if( (*ngubconsGFC1) > 0 )
3419 {
3420 SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3421 }
3422
3423 /* free temporary memory */
3424#if GUBSPLITGNC1GUBS
3425 ngubconss = origngubconss;
3426#endif
3427 SCIPfreeBufferArray(scip, &nC1varsingubcons);
3428 SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3429 SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3430
3431 return SCIP_OKAY;
3432}
3433
3434/** enlarges minweight table to at least the given length */
3435static
3437 SCIP* scip, /**< SCIP data structure */
3438 SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3439 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3440 int* minweightssize, /**< pointer to current size of minweights table */
3441 int newlen /**< new length of minweights table */
3442 )
3443{
3444 int j;
3445
3446 assert(minweightsptr != NULL);
3447 assert(*minweightsptr != NULL);
3448 assert(minweightslen != NULL);
3449 assert(*minweightslen >= 0);
3450 assert(minweightssize != NULL);
3451 assert(*minweightssize >= 0);
3452
3453 if( newlen > *minweightssize )
3454 {
3455 int newsize;
3456
3457 /* reallocate table memory */
3458 newsize = SCIPcalcMemGrowSize(scip, newlen);
3459 SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3460 *minweightssize = newsize;
3461 }
3462 assert(newlen <= *minweightssize);
3463
3464 /* initialize new elements */
3465 for( j = *minweightslen; j < newlen; ++j )
3466 (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3467 *minweightslen = newlen;
3468
3469 return SCIP_OKAY;
3470}
3471
3472/** lifts given inequality
3473 * sum_{j in M_1} x_j <= alpha_0
3474 * valid for
3475 * S^0 = { x in {0,1}^|M_1| : sum_{j in M_1} a_j x_j <= a_0 - sum_{j in M_2} a_j }
3476 * to a valid inequality
3477 * sum_{j in M_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in M_2} alpha_j x_j + sum_{j in R} alpha_j x_j
3478 * <= alpha_0 + sum_{j in M_2} alpha_j
3479 * for
3480 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3481 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3482 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3483 * extended weight inequalities.
3484 */
3485static
3487 SCIP* scip, /**< SCIP data structure */
3488 SCIP_VAR** vars, /**< variables in knapsack constraint */
3489 int nvars, /**< number of variables in knapsack constraint */
3490 int ntightened, /**< number of variables with tightened upper bound */
3491 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3492 SCIP_Longint capacity, /**< capacity of knapsack */
3493 SCIP_Real* solvals, /**< solution values of all problem variables */
3494 int* varsM1, /**< variables in M_1 */
3495 int* varsM2, /**< variables in M_2 */
3496 int* varsF, /**< variables in F */
3497 int* varsR, /**< variables in R */
3498 int nvarsM1, /**< number of variables in M_1 */
3499 int nvarsM2, /**< number of variables in M_2 */
3500 int nvarsF, /**< number of variables in F */
3501 int nvarsR, /**< number of variables in R */
3502 int alpha0, /**< rights hand side of given valid inequality */
3503 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3504 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3505 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3506 )
3507{
3508 SCIP_Longint* minweights;
3509 SCIP_Real* sortkeys;
3510 SCIP_Longint fixedonesweight;
3511 int minweightssize;
3512 int minweightslen;
3513 int j;
3514 int w;
3515
3516 assert(scip != NULL);
3517 assert(vars != NULL);
3518 assert(nvars >= 0);
3519 assert(weights != NULL);
3520 assert(capacity >= 0);
3521 assert(solvals != NULL);
3522 assert(varsM1 != NULL);
3523 assert(varsM2 != NULL);
3524 assert(varsF != NULL);
3525 assert(varsR != NULL);
3526 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3527 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3528 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3529 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3530 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3531 assert(alpha0 >= 0);
3532 assert(liftcoefs != NULL);
3533 assert(cutact != NULL);
3534 assert(liftrhs != NULL);
3535
3536 /* allocates temporary memory */
3537 minweightssize = nvarsM1 + 1;
3538 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3539 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3540
3541 /* initializes data structures */
3542 BMSclearMemoryArray(liftcoefs, nvars);
3543 *cutact = 0.0;
3544
3545 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3546 * and calculates activity of the current valid inequality
3547 */
3548 for( j = 0; j < nvarsM1; j++ )
3549 {
3550 assert(liftcoefs[varsM1[j]] == 0);
3551 liftcoefs[varsM1[j]] = 1;
3552 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3553 (*cutact) += solvals[varsM1[j]];
3554 }
3555
3556 SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3557
3558 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3559 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3560 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3561 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3562 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3563 */
3564 minweights[0] = 0;
3565 for( w = 1; w <= nvarsM1; w++ )
3566 minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3567 minweightslen = nvarsM1 + 1;
3568
3569 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3570 fixedonesweight = 0;
3571 for( j = 0; j < nvarsM2; j++ )
3572 fixedonesweight += weights[varsM2[j]];
3573 assert(fixedonesweight >= 0);
3574
3575 /* initializes right hand side of lifted valid inequality */
3576 *liftrhs = alpha0;
3577
3578 /* sequentially up-lifts all variables in F: */
3579 for( j = 0; j < nvarsF; j++ )
3580 {
3581 SCIP_Longint weight;
3582 int liftvar;
3583 int liftcoef;
3584 int z;
3585
3586 liftvar = varsF[j];
3587 weight = weights[liftvar];
3588 assert(liftvar >= 0 && liftvar < nvars);
3589 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3590 assert(weight > 0);
3591
3592 /* knapsack problem is infeasible:
3593 * sets z = 0
3594 */
3595 if( capacity - fixedonesweight - weight < 0 )
3596 {
3597 z = 0;
3598 }
3599 /* knapsack problem is feasible:
3600 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3601 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3602 */
3603 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3604 {
3605 z = *liftrhs;
3606 }
3607 /* knapsack problem is feasible:
3608 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3609 */
3610 else
3611 {
3612 int left;
3613 int right;
3614 int middle;
3615
3616 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3617 left = 0;
3618 right = (*liftrhs) + 1;
3619 while( left < right - 1 )
3620 {
3621 middle = (left + right) / 2;
3622 assert(0 <= middle && middle < minweightslen);
3623 if( minweights[middle] <= capacity - fixedonesweight - weight )
3624 left = middle;
3625 else
3626 right = middle;
3627 }
3628 assert(left == right - 1);
3629 assert(0 <= left && left < minweightslen);
3630 assert(minweights[left] <= capacity - fixedonesweight - weight );
3631 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3632
3633 /* now z = left */
3634 z = left;
3635 assert(z <= *liftrhs);
3636 }
3637
3638 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3639 liftcoef = (*liftrhs) - z;
3640 liftcoefs[liftvar] = liftcoef;
3641 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3642
3643 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3644 if( liftcoef == 0 )
3645 continue;
3646
3647 /* updates activity of current valid inequality */
3648 (*cutact) += liftcoef * solvals[liftvar];
3649
3650 /* enlarges current minweight table:
3651 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3652 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3653 * and sets minweights_i[w] = infinity for
3654 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3655 */
3656 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3657
3658 /* updates minweight table: minweight_i+1[w] =
3659 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3660 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3661 */
3662 for( w = minweightslen - 1; w >= 0; w-- )
3663 {
3664 SCIP_Longint min;
3665 if( w < liftcoef )
3666 {
3667 min = MIN(minweights[w], weight);
3668 minweights[w] = min;
3669 }
3670 else
3671 {
3672 assert(w >= liftcoef);
3673 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3674 minweights[w] = min;
3675 }
3676 }
3677 }
3678 assert(minweights[0] == 0);
3679
3680 /* sequentially down-lifts all variables in M_2: */
3681 for( j = 0; j < nvarsM2; j++ )
3682 {
3683 SCIP_Longint weight;
3684 int liftvar;
3685 int liftcoef;
3686 int left;
3687 int right;
3688 int middle;
3689 int z;
3690
3691 liftvar = varsM2[j];
3692 weight = weights[liftvar];
3693 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3694 assert(liftvar >= 0 && liftvar < nvars);
3695 assert(weight > 0);
3696
3697 /* uses binary search to find
3698 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3699 */
3700 left = 0;
3701 right = minweightslen;
3702 while( left < right - 1 )
3703 {
3704 middle = (left + right) / 2;
3705 assert(0 <= middle && middle < minweightslen);
3706 if( minweights[middle] <= capacity - fixedonesweight + weight )
3707 left = middle;
3708 else
3709 right = middle;
3710 }
3711 assert(left == right - 1);
3712 assert(0 <= left && left < minweightslen);
3713 assert(minweights[left] <= capacity - fixedonesweight + weight );
3714 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3715
3716 /* now z = left */
3717 z = left;
3718 assert(z >= *liftrhs);
3719
3720 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3721 liftcoef = z - (*liftrhs);
3722 liftcoefs[liftvar] = liftcoef;
3723 assert(liftcoef >= 0);
3724
3725 /* updates sum of weights of variables fixed to one */
3726 fixedonesweight -= weight;
3727
3728 /* updates right-hand side of current valid inequality */
3729 (*liftrhs) += liftcoef;
3730 assert(*liftrhs >= alpha0);
3731
3732 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3733 if( liftcoef == 0 )
3734 continue;
3735
3736 /* updates activity of current valid inequality */
3737 (*cutact) += liftcoef * solvals[liftvar];
3738
3739 /* enlarges current minweight table:
3740 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3741 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3742 * and sets minweights_i[w] = infinity for
3743 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3744 */
3745 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3746
3747 /* updates minweight table: minweight_i+1[w] =
3748 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3749 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3750 */
3751 for( w = minweightslen - 1; w >= 0; w-- )
3752 {
3753 SCIP_Longint min;
3754 if( w < liftcoef )
3755 {
3756 min = MIN(minweights[w], weight);
3757 minweights[w] = min;
3758 }
3759 else
3760 {
3761 assert(w >= liftcoef);
3762 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3763 minweights[w] = min;
3764 }
3765 }
3766 }
3767 assert(fixedonesweight == 0);
3768 assert(*liftrhs >= alpha0);
3769
3770 /* sequentially up-lifts all variables in R: */
3771 for( j = 0; j < nvarsR; j++ )
3772 {
3773 SCIP_Longint weight;
3774 int liftvar;
3775 int liftcoef;
3776 int z;
3777
3778 liftvar = varsR[j];
3779 weight = weights[liftvar];
3780 assert(liftvar >= 0 && liftvar < nvars);
3781 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3782 assert(weight > 0);
3783 assert(capacity - weight >= 0);
3784 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3785
3786 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3787 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3788 */
3789 if( minweights[*liftrhs] <= capacity - weight )
3790 {
3791 z = *liftrhs;
3792 }
3793 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3794 */
3795 else
3796 {
3797 int left;
3798 int right;
3799 int middle;
3800
3801 left = 0;
3802 right = (*liftrhs) + 1;
3803 while( left < right - 1)
3804 {
3805 middle = (left + right) / 2;
3806 assert(0 <= middle && middle < minweightslen);
3807 if( minweights[middle] <= capacity - weight )
3808 left = middle;
3809 else
3810 right = middle;
3811 }
3812 assert(left == right - 1);
3813 assert(0 <= left && left < minweightslen);
3814 assert(minweights[left] <= capacity - weight );
3815 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3816
3817 /* now z = left */
3818 z = left;
3819 assert(z <= *liftrhs);
3820 }
3821
3822 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3823 liftcoef = (*liftrhs) - z;
3824 liftcoefs[liftvar] = liftcoef;
3825 assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3826
3827 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3828 if( liftcoef == 0 )
3829 continue;
3830
3831 /* updates activity of current valid inequality */
3832 (*cutact) += liftcoef * solvals[liftvar];
3833
3834 /* updates minweight table: minweight_i+1[w] =
3835 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3836 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3837 */
3838 for( w = *liftrhs; w >= 0; w-- )
3839 {
3840 SCIP_Longint min;
3841 if( w < liftcoef )
3842 {
3843 min = MIN(minweights[w], weight);
3844 minweights[w] = min;
3845 }
3846 else
3847 {
3848 assert(w >= liftcoef);
3849 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3850 minweights[w] = min;
3851 }
3852 }
3853 }
3854
3855 /* frees temporary memory */
3856 SCIPfreeBufferArray(scip, &sortkeys);
3857 SCIPfreeBufferArray(scip, &minweights);
3858
3859 return SCIP_OKAY;
3860}
3861
3862/** adds two minweight values in a safe way, i.e,, ensures no overflow */
3863static
3865 SCIP_Longint val1, /**< first value to add */
3866 SCIP_Longint val2 /**< second value to add */
3867 )
3868{
3869 assert(val1 >= 0);
3870 assert(val2 >= 0);
3871
3872 if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3873 return SCIP_LONGINT_MAX;
3874 else
3875 {
3876 assert(val1 <= SCIP_LONGINT_MAX - val2);
3877 return (val1 + val2);
3878 }
3879}
3880
3881/** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3882static
3884 SCIP_Longint* minweights, /**< minweight table to compute */
3885 SCIP_Longint* finished, /**< given finished table */
3886 SCIP_Longint* unfinished, /**< given unfinished table */
3887 int minweightslen /**< length of minweight, finished, and unfinished tables */
3888 )
3889{
3890 int w1;
3891 int w2;
3892
3893 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3894 * note that finished and unfished arrays sorted by non-decreasing weight
3895 */
3896
3897 /* initialize minweight with w2 = 0 */
3898 w2 = 0;
3899 assert(unfinished[w2] == 0);
3900 for( w1 = 0; w1 < minweightslen; w1++ )
3901 minweights[w1] = finished[w1];
3902
3903 /* consider w2 = 1, ..., minweightslen-1 */
3904 for( w2 = 1; w2 < minweightslen; w2++ )
3905 {
3906 if( unfinished[w2] >= SCIP_LONGINT_MAX )
3907 break;
3908
3909 for( w1 = 0; w1 < minweightslen - w2; w1++ )
3910 {
3911 SCIP_Longint temp;
3912
3913 temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3914 if( temp <= minweights[w1+w2] )
3915 minweights[w1+w2] = temp;
3916 }
3917 }
3918}
3919
3920/** lifts given inequality
3921 * sum_{j in C_1} x_j <= alpha_0
3922 * valid for
3923 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j;
3924 * sum_{j in Q_i} x_j <= 1, forall i in I }
3925 * to a valid inequality
3926 * sum_{j in C_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in C_2} alpha_j x_j + sum_{j in R} alpha_j x_j
3927 * <= alpha_0 + sum_{j in C_2} alpha_j
3928 * for
3929 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0; sum_{j in Q_i} x_j <= 1, forall i in I };
3930 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3931 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3932 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3933 */
3934static
3936 SCIP* scip, /**< SCIP data structure */
3937 SCIP_GUBSET* gubset, /**< GUB set data structure */
3938 SCIP_VAR** vars, /**< variables in knapsack constraint */
3939 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3940 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3941 SCIP_Longint capacity, /**< capacity of knapsack */
3942 SCIP_Real* solvals, /**< solution values of all knapsack variables */
3943 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3944 int* gubconsGC2, /**< GUBs in GC2 */
3945 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3946 int* gubconsGR, /**< GUBs in GR */
3947 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3948 int ngubconsGC2, /**< number of GUBs in GC2 */
3949 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3950 int ngubconsGR, /**< number of GUBs in GR */
3951 int alpha0, /**< rights hand side of given valid inequality */
3952 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3953 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3954 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3955 int maxgubvarssize /**< maximal size of GUB constraints */
3956 )
3957{
3958 SCIP_Longint* minweights;
3959 SCIP_Longint* finished;
3960 SCIP_Longint* unfinished;
3961 int* gubconsGOC1;
3962 int* gubconsGNC1;
3963 int* liftgubvars;
3964 SCIP_Longint fixedonesweight;
3965 SCIP_Longint weight;
3966 SCIP_Longint weightdiff1;
3967 SCIP_Longint weightdiff2;
3968 SCIP_Longint min;
3969 int minweightssize;
3970 int minweightslen;
3971 int nvars;
3972 int varidx;
3973 int liftgubconsidx;
3974 int liftvar;
3975 int sumliftcoef;
3976 int liftcoef;
3977 int ngubconsGOC1;
3978 int ngubconsGNC1;
3979 int left;
3980 int right;
3981 int middle;
3982 int nliftgubvars;
3983 int tmplen;
3984 int tmpsize;
3985 int j;
3986 int k;
3987 int w;
3988 int z;
3989#ifndef NDEBUG
3990 int ngubconss;
3991 int nliftgubC1;
3992
3993 assert(gubset != NULL);
3994 ngubconss = gubset->ngubconss;
3995#else
3996 assert(gubset != NULL);
3997#endif
3998
3999 nvars = gubset->nvars;
4000
4001 assert(scip != NULL);
4002 assert(vars != NULL);
4003 assert(nvars >= 0);
4004 assert(weights != NULL);
4005 assert(capacity >= 0);
4006 assert(solvals != NULL);
4007 assert(gubconsGC1 != NULL);
4008 assert(gubconsGC2 != NULL);
4009 assert(gubconsGFC1 != NULL);
4010 assert(gubconsGR != NULL);
4011 assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4012 assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4013 assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4014 assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4015 assert(alpha0 >= 0);
4016 assert(liftcoefs != NULL);
4017 assert(cutact != NULL);
4018 assert(liftrhs != NULL);
4019
4020 minweightssize = ngubconsGC1+1;
4021
4022 /* allocates temporary memory */
4023 SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4024 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4025 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4026 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4027 SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4028 SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4029
4030 /* initializes data structures */
4031 BMSclearMemoryArray(liftcoefs, nvars);
4032 *cutact = 0.0;
4033
4034 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4035 * valid inequality
4036 */
4037 ngubconsGOC1 = 0;
4038 ngubconsGNC1 = 0;
4039 for( j = 0; j < ngubconsGC1; j++ )
4040 {
4041 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4042 {
4043 gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4044 ngubconsGOC1++;
4045 }
4046 else
4047 {
4048 assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4049 gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4050 ngubconsGNC1++;
4051 }
4052 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4053 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4054 {
4055 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4056 assert(varidx >= 0 && varidx < nvars);
4057 assert(liftcoefs[varidx] == 0);
4058
4059 liftcoefs[varidx] = 1;
4060 (*cutact) += solvals[varidx];
4061 }
4062 assert(k >= 1);
4063 }
4064 assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4065 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4066
4067 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4068 * - finished_i[w] =
4069 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4070 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4071 * sum_{j in Q_k} x_j <= 1
4072 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4073 * - unfinished_i[w] =
4074 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4075 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4076 * sum_{j in Q_k} x_j <= 1
4077 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4078 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4079 */
4080
4081 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4082 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4083 * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
4084 * comes from the first variable in the GUB
4085 */
4086 assert(ngubconsGOC1 <= ngubconsGC1);
4087 finished[0] = 0;
4088 for( w = 1; w <= ngubconsGOC1; w++ )
4089 {
4090 liftgubconsidx = gubconsGOC1[w-1];
4091
4092 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4093 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4094
4095 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4096
4097 assert(varidx >= 0 && varidx < nvars);
4098 assert(liftcoefs[varidx] == 1);
4099
4100 min = weights[varidx];
4101 finished[w] = finished[w-1] + min;
4102
4103#ifndef NDEBUG
4104 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4105 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4106 {
4107 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4108 assert(varidx >= 0 && varidx < nvars);
4109 assert(liftcoefs[varidx] == 1);
4110 assert(weights[varidx] >= min);
4111 }
4112#endif
4113 }
4114 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4115 finished[w] = SCIP_LONGINT_MAX;
4116
4117 /* initialize unfinished table; note that variables in GNC1 GUBs
4118 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4119 * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
4120 * comes from the first variable in the GUB
4121 */
4122 assert(ngubconsGNC1 <= ngubconsGC1);
4123 unfinished[0] = 0;
4124 for( w = 1; w <= ngubconsGNC1; w++ )
4125 {
4126 liftgubconsidx = gubconsGNC1[w-1];
4127
4128 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4129 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4130
4131 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4132
4133 assert(varidx >= 0 && varidx < nvars);
4134 assert(liftcoefs[varidx] == 1);
4135
4136 min = weights[varidx];
4137 unfinished[w] = unfinished[w-1] + min;
4138
4139#ifndef NDEBUG
4140 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4141 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4142 {
4143 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4144 assert(varidx >= 0 && varidx < nvars);
4145 assert(liftcoefs[varidx] == 1);
4146 assert(weights[varidx] >= min );
4147 }
4148#endif
4149 }
4150 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4151 unfinished[w] = SCIP_LONGINT_MAX;
4152
4153 /* initialize minweights table; note that variables in GC1 GUBs
4154 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4155 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4156 * consuming) because is it has to be build using weights from C1 only.
4157 */
4158 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4159 minweights[0] = 0;
4160 for( w = 1; w <= ngubconsGC1; w++ )
4161 {
4162 liftgubconsidx = gubconsGC1[w-1];
4163
4164 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4165 || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4166 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4167
4168 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4169
4170 assert(varidx >= 0 && varidx < nvars);
4171 assert(liftcoefs[varidx] == 1);
4172
4173 min = weights[varidx];
4174 minweights[w] = minweights[w-1] + min;
4175
4176#ifndef NDEBUG
4177 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4178 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4179 {
4180 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4181 assert(varidx >= 0 && varidx < nvars);
4182 assert(liftcoefs[varidx] == 1);
4183 assert(weights[varidx] >= min);
4184 }
4185#endif
4186 }
4187 minweightslen = ngubconsGC1 + 1;
4188
4189 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4190 fixedonesweight = 0;
4191 for( j = 0; j < ngubconsGC2; j++ )
4192 {
4193 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4194
4195 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4196 assert(varidx >= 0 && varidx < nvars);
4197 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4198
4199 fixedonesweight += weights[varidx];
4200 }
4201 assert(fixedonesweight >= 0);
4202
4203 /* initializes right hand side of lifted valid inequality */
4204 *liftrhs = alpha0;
4205
4206 /* sequentially up-lifts all variables in GFC1 GUBs */
4207 for( j = 0; j < ngubconsGFC1; j++ )
4208 {
4209 liftgubconsidx = gubconsGFC1[j];
4210 assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4211
4212 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4213 * compute minweight table via updated unfinished table and aleady upto date finished table;
4214 */
4215 k = 0;
4216 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4217 {
4218 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4219 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4220 assert(ngubconsGNC1 > 0);
4221
4222 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4223 * are considered for the lifting, i.e., not capacity exceeding
4224 */
4225 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4226 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4227 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4228 assert(k >= 1);
4229
4230 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4231 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4232 */
4233 weight = weights[liftgubvars[0]];
4234
4235 weightdiff2 = unfinished[ngubconsGNC1] - weight;
4236 unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4237 for( w = ngubconsGNC1-1; w >= 1; w-- )
4238 {
4239 weightdiff1 = weightdiff2;
4240 weightdiff2 = unfinished[w] - weight;
4241
4242 if( unfinished[w] < weightdiff1 )
4243 unfinished[w] = weightdiff1;
4244 else
4245 break;
4246 }
4247 ngubconsGNC1--;
4248
4249 /* computes minweights table by combining unfished and fished tables */
4250 computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4251 assert(minweights[0] == 0);
4252 }
4253 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4254 * are therefore not in the unfinished table
4255 */
4256 else
4257 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4258
4259#ifndef NDEBUG
4260 nliftgubC1 = k;
4261#endif
4262 nliftgubvars = k;
4263 sumliftcoef = 0;
4264
4265 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4266 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4267 {
4268 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4269 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4270 {
4271 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4272 weight = weights[liftvar];
4273 assert(weight > 0);
4274 assert(liftvar >= 0 && liftvar < nvars);
4275 assert(capacity - weight >= 0);
4276
4277 /* put variable into array of variables in GUB that are considered for the lifting,
4278 * i.e., not capacity exceeding
4279 */
4280 liftgubvars[nliftgubvars] = liftvar;
4281 nliftgubvars++;
4282
4283 /* knapsack problem is infeasible:
4284 * sets z = 0
4285 */
4286 if( capacity - fixedonesweight - weight < 0 )
4287 {
4288 z = 0;
4289 }
4290 /* knapsack problem is feasible:
4291 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4292 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4293 */
4294 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4295 {
4296 z = *liftrhs;
4297 }
4298 /* knapsack problem is feasible:
4299 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4300 */
4301 else
4302 {
4303 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4304 left = 0;
4305 right = (*liftrhs) + 1;
4306 while( left < right - 1 )
4307 {
4308 middle = (left + right) / 2;
4309 assert(0 <= middle && middle < minweightslen);
4310 if( minweights[middle] <= capacity - fixedonesweight - weight )
4311 left = middle;
4312 else
4313 right = middle;
4314 }
4315 assert(left == right - 1);
4316 assert(0 <= left && left < minweightslen);
4317 assert(minweights[left] <= capacity - fixedonesweight - weight);
4318 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4319
4320 /* now z = left */
4321 z = left;
4322 assert(z <= *liftrhs);
4323 }
4324
4325 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4326 liftcoef = (*liftrhs) - z;
4327 liftcoefs[liftvar] = liftcoef;
4328 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4329
4330 /* updates activity of current valid inequality */
4331 (*cutact) += liftcoef * solvals[liftvar];
4332
4333 /* updates sum of all lifting coefficients in GUB */
4334 sumliftcoef += liftcoefs[liftvar];
4335 }
4336 else
4337 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4338 }
4339 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4340 assert(nliftgubvars > nliftgubC1);
4341
4342 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4343 * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4344 * not needed for GF GUBs
4345 */
4346 if( sumliftcoef == 0 )
4347 {
4348 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4349 {
4350 weight = weights[liftgubvars[0]];
4351 /* update finished table and minweights table by applying special case of
4352 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4353 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4354 */
4355 for( w = minweightslen-1; w >= 1; w-- )
4356 {
4357 SCIP_Longint tmpval;
4358
4359 tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4360 finished[w] = MIN(finished[w], tmpval);
4361
4362 tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4363 minweights[w] = MIN(minweights[w], tmpval);
4364 }
4365 }
4366 else
4367 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4368
4369 continue;
4370 }
4371
4372 /* enlarges current minweights tables(finished, unfinished, minweights):
4373 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4374 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4375 * and sets minweights_i[w] = infinity for
4376 * w = |gubconsGC1| + sum_{k=1,2,..,i-1}sum_{j in Q_k} alpha_j+1,..,|C1| + sum_{k=1,2,..,i}sum_{j in Q_k} alpha_j
4377 */
4378 tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4379 tmpsize = minweightssize;
4380 SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4381 tmplen = minweightslen;
4382 tmpsize = minweightssize;
4383 SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4384 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4385
4386 /* update finished table and minweight table;
4387 * note that instead of computing minweight table from updated finished and updated unfinished table again
4388 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4389 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4390 * not needed because only finished table changed at this point and the change was "adding" one weight)
4391 *
4392 * update formular for minweight table is: minweight_i+1[w] =
4393 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4394 * formular for finished table has the same pattern.
4395 */
4396 for( w = minweightslen-1; w >= 0; w-- )
4397 {
4398 SCIP_Longint minminweight;
4399 SCIP_Longint minfinished;
4400
4401 for( k = 0; k < nliftgubvars; k++ )
4402 {
4403 liftcoef = liftcoefs[liftgubvars[k]];
4404 weight = weights[liftgubvars[k]];
4405
4406 if( w < liftcoef )
4407 {
4408 minfinished = MIN(finished[w], weight);
4409 minminweight = MIN(minweights[w], weight);
4410
4411 finished[w] = minfinished;
4412 minweights[w] = minminweight;
4413 }
4414 else
4415 {
4416 SCIP_Longint tmpval;
4417
4418 assert(w >= liftcoef);
4419
4420 tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4421 minfinished = MIN(finished[w], tmpval);
4422
4423 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4424 minminweight = MIN(minweights[w], tmpval);
4425
4426 finished[w] = minfinished;
4427 minweights[w] = minminweight;
4428 }
4429 }
4430 }
4431 assert(minweights[0] == 0);
4432 }
4433 assert(ngubconsGNC1 == 0);
4434
4435 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4436 * therefore, only work with minweight table from here on
4437 */
4438
4439 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4440 for( j = 0; j < ngubconsGC2; j++ )
4441 {
4442 liftgubconsidx = gubconsGC2[j];
4443
4444 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4445 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4446 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4447 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4448
4449 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4450 weight = weights[liftvar];
4451
4452 assert(liftvar >= 0 && liftvar < nvars);
4453 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4454 assert(weight > 0);
4455
4456 /* uses binary search to find
4457 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4458 */
4459 left = 0;
4460 right = minweightslen;
4461 while( left < right - 1 )
4462 {
4463 middle = (left + right) / 2;
4464 assert(0 <= middle && middle < minweightslen);
4465 if( minweights[middle] <= capacity - fixedonesweight + weight )
4466 left = middle;
4467 else
4468 right = middle;
4469 }
4470 assert(left == right - 1);
4471 assert(0 <= left && left < minweightslen);
4472 assert(minweights[left] <= capacity - fixedonesweight + weight);
4473 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4474
4475 /* now z = left */
4476 z = left;
4477 assert(z >= *liftrhs);
4478
4479 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4480 liftcoef = z - (*liftrhs);
4481 liftcoefs[liftvar] = liftcoef;
4482 assert(liftcoef >= 0);
4483
4484 /* updates sum of weights of variables fixed to one */
4485 fixedonesweight -= weight;
4486
4487 /* updates right-hand side of current valid inequality */
4488 (*liftrhs) += liftcoef;
4489 assert(*liftrhs >= alpha0);
4490
4491 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4492 if( liftcoef == 0 )
4493 continue;
4494
4495 /* updates activity of current valid inequality */
4496 (*cutact) += liftcoef * solvals[liftvar];
4497
4498 /* enlarges current minweight table:
4499 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4500 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4501 * and sets minweights_i[w] = infinity for
4502 * w = |C1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 , ... , |C1| + sum_{k=1,2,...,i}sum_{j in Q_k} alpha_j
4503 */
4504 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4505
4506 /* updates minweight table: minweight_i+1[w] =
4507 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4508 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4509 */
4510 for( w = minweightslen - 1; w >= 0; w-- )
4511 {
4512 if( w < liftcoef )
4513 {
4514 min = MIN(minweights[w], weight);
4515 minweights[w] = min;
4516 }
4517 else
4518 {
4519 SCIP_Longint tmpval;
4520
4521 assert(w >= liftcoef);
4522
4523 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4524 min = MIN(minweights[w], tmpval);
4525 minweights[w] = min;
4526 }
4527 }
4528 }
4529 assert(fixedonesweight == 0);
4530 assert(*liftrhs >= alpha0);
4531
4532 /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4533 for( j = 0; j < ngubconsGR; j++ )
4534 {
4535 liftgubconsidx = gubconsGR[j];
4536
4537 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4538 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4539
4540 sumliftcoef = 0;
4541 nliftgubvars = 0;
4542 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4543 {
4544 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4545 {
4546 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4547 weight = weights[liftvar];
4548 assert(weight > 0);
4549 assert(liftvar >= 0 && liftvar < nvars);
4550 assert(capacity - weight >= 0);
4551 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4552
4553 /* put variable into array of variables in GUB that are considered for the lifting,
4554 * i.e., not capacity exceeding
4555 */
4556 liftgubvars[nliftgubvars] = liftvar;
4557 nliftgubvars++;
4558
4559 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4560 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4561 */
4562 if( minweights[*liftrhs] <= capacity - weight )
4563 {
4564 z = *liftrhs;
4565 }
4566 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4567 */
4568 else
4569 {
4570 left = 0;
4571 right = (*liftrhs) + 1;
4572 while( left < right - 1 )
4573 {
4574 middle = (left + right) / 2;
4575 assert(0 <= middle && middle < minweightslen);
4576 if( minweights[middle] <= capacity - weight )
4577 left = middle;
4578 else
4579 right = middle;
4580 }
4581 assert(left == right - 1);
4582 assert(0 <= left && left < minweightslen);
4583 assert(minweights[left] <= capacity - weight);
4584 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4585
4586 /* now z = left */
4587 z = left;
4588 assert(z <= *liftrhs);
4589 }
4590 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4591 liftcoef = (*liftrhs) - z;
4592 liftcoefs[liftvar] = liftcoef;
4593 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4594
4595 /* updates activity of current valid inequality */
4596 (*cutact) += liftcoef * solvals[liftvar];
4597
4598 /* updates sum of all lifting coefficients in GUB */
4599 sumliftcoef += liftcoefs[liftvar];
4600 }
4601 else
4602 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4603 }
4604 assert(nliftgubvars >= 1); /* at least one variable is in R */
4605
4606 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4607 if( sumliftcoef == 0 )
4608 continue;
4609
4610 /* updates minweight table: minweight_i+1[w] =
4611 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4612 */
4613 for( w = *liftrhs; w >= 0; w-- )
4614 {
4615 for( k = 0; k < nliftgubvars; k++ )
4616 {
4617 liftcoef = liftcoefs[liftgubvars[k]];
4618 weight = weights[liftgubvars[k]];
4619
4620 if( w < liftcoef )
4621 {
4622 min = MIN(minweights[w], weight);
4623 minweights[w] = min;
4624 }
4625 else
4626 {
4627 SCIP_Longint tmpval;
4628
4629 assert(w >= liftcoef);
4630
4631 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4632 min = MIN(minweights[w], tmpval);
4633 minweights[w] = min;
4634 }
4635 }
4636 }
4637 assert(minweights[0] == 0);
4638 }
4639
4640 /* frees temporary memory */
4641 SCIPfreeBufferArray(scip, &minweights);
4642 SCIPfreeBufferArray(scip, &finished);
4643 SCIPfreeBufferArray(scip, &unfinished);
4644 SCIPfreeBufferArray(scip, &liftgubvars);
4645 SCIPfreeBufferArray(scip, &gubconsGOC1 );
4646 SCIPfreeBufferArray(scip, &gubconsGNC1);
4647
4648 return SCIP_OKAY;
4649}
4650
4651/** lifts given minimal cover inequality
4652 * \f[
4653 * \sum_{j \in C} x_j \leq |C| - 1
4654 * \f]
4655 * valid for
4656 * \f[
4657 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4658 * \f]
4659 * to a valid inequality
4660 * \f[
4661 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4662 * \f]
4663 * for
4664 * \f[
4665 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4666 * \f]
4667 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4668 */
4669static
4671 SCIP* scip, /**< SCIP data structure */
4672 SCIP_VAR** vars, /**< variables in knapsack constraint */
4673 int nvars, /**< number of variables in knapsack constraint */
4674 int ntightened, /**< number of variables with tightened upper bound */
4675 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4676 SCIP_Longint capacity, /**< capacity of knapsack */
4677 SCIP_Real* solvals, /**< solution values of all problem variables */
4678 int* covervars, /**< cover variables */
4679 int* noncovervars, /**< noncover variables */
4680 int ncovervars, /**< number of cover variables */
4681 int nnoncovervars, /**< number of noncover variables */
4682 SCIP_Longint coverweight, /**< weight of cover */
4683 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4684 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4685 )
4686{
4687 SCIP_Longint* maxweightsums;
4688 SCIP_Longint* intervalends;
4689 SCIP_Longint* rhos;
4690 SCIP_Real* sortkeys;
4691 SCIP_Longint lambda;
4692 int j;
4693 int h;
4694
4695 assert(scip != NULL);
4696 assert(vars != NULL);
4697 assert(nvars >= 0);
4698 assert(weights != NULL);
4699 assert(capacity >= 0);
4700 assert(solvals != NULL);
4701 assert(covervars != NULL);
4702 assert(noncovervars != NULL);
4703 assert(ncovervars > 0 && ncovervars <= nvars);
4704 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4705 assert(ncovervars + nnoncovervars == nvars - ntightened);
4706 assert(liftcoefs != NULL);
4707 assert(cutact != NULL);
4708
4709 /* allocates temporary memory */
4710 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4711 SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4712 SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4713 SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4714
4715 /* initializes data structures */
4716 BMSclearMemoryArray(liftcoefs, nvars);
4717 *cutact = 0.0;
4718
4719 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4720 * and calculates activity of current valid inequality
4721 */
4722 for( j = 0; j < ncovervars; j++ )
4723 {
4724 assert(liftcoefs[covervars[j]] == 0.0);
4725 liftcoefs[covervars[j]] = 1.0;
4726 sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4727 (*cutact) += solvals[covervars[j]];
4728 }
4729 SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4730
4731 /* calculates weight excess of cover C */
4732 lambda = coverweight - capacity;
4733 assert(lambda > 0);
4734
4735 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4736 maxweightsums[0] = 0;
4737 for( h = 1; h <= ncovervars; h++ )
4738 {
4739 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4740 intervalends[h-1] = maxweightsums[h] - lambda;
4741 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4742 }
4743
4744 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4745 for( j = 0; j < nnoncovervars; j++ )
4746 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4747 SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4748
4749 /* calculates lifting coefficient for all variables in N\C */
4750 h = 0;
4751 for( j = 0; j < nnoncovervars; j++ )
4752 {
4753 int liftvar;
4754 SCIP_Longint weight;
4755 SCIP_Real liftcoef;
4756
4757 liftvar = noncovervars[j];
4758 weight = weights[liftvar];
4759
4760 while( intervalends[h] < weight )
4761 h++;
4762
4763 if( h == 0 )
4764 liftcoef = h;
4765 else
4766 {
4767 if( weight <= intervalends[h-1] + rhos[h] )
4768 {
4769 SCIP_Real tmp1;
4770 SCIP_Real tmp2;
4771 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4772 tmp2 = (SCIP_Real) rhos[1];
4773 liftcoef = h - ( tmp1 / tmp2 );
4774 }
4775 else
4776 liftcoef = h;
4777 }
4778
4779 /* sets lifting coefficient */
4780 assert(liftcoefs[liftvar] == 0.0);
4781 liftcoefs[liftvar] = liftcoef;
4782
4783 /* updates activity of current valid inequality */
4784 (*cutact) += liftcoef * solvals[liftvar];
4785 }
4786
4787 /* frees temporary memory */
4788 SCIPfreeBufferArray(scip, &rhos);
4789 SCIPfreeBufferArray(scip, &intervalends);
4790 SCIPfreeBufferArray(scip, &maxweightsums);
4791 SCIPfreeBufferArray(scip, &sortkeys);
4792
4793 return SCIP_OKAY;
4794}
4795
4796
4797/** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4798 * given knapsack problem
4799*/
4800static
4802 SCIP* scip, /**< SCIP data structure */
4803 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4804 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4805 SCIP_VAR** vars, /**< variables in knapsack constraint */
4806 int nvars, /**< number of variables in knapsack constraint */
4807 int ntightened, /**< number of variables with tightened upper bound */
4808 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4809 SCIP_Longint capacity, /**< capacity of knapsack */
4810 SCIP_Real* solvals, /**< solution values of all problem variables */
4811 int* mincovervars, /**< mincover variables */
4812 int* nonmincovervars, /**< nonmincover variables */
4813 int nmincovervars, /**< number of mincover variables */
4814 int nnonmincovervars, /**< number of nonmincover variables */
4815 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4816 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4817 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4818 int* ncuts /**< pointer to add up the number of found cuts */
4819 )
4820{
4821 int* varsC1;
4822 int* varsC2;
4823 int* varsF;
4824 int* varsR;
4825 int nvarsC1;
4826 int nvarsC2;
4827 int nvarsF;
4828 int nvarsR;
4829 SCIP_Real cutact;
4830 int* liftcoefs;
4831 int liftrhs;
4832
4833 assert( cutoff != NULL );
4834 *cutoff = FALSE;
4835
4836 /* allocates temporary memory */
4841 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4842
4843 /* gets partition (C_1,C_2) of C, i.e. C_1 & C_2 = C and C_1 cap C_2 = emptyset, with C_1 not empty; chooses partition
4844 * as follows
4845 * C_2 = { j in C : x*_j = 1 } and
4846 * C_1 = C\C_2
4847 */
4848 getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4849 assert(nvarsC1 + nvarsC2 == nmincovervars);
4850 assert(nmincovervars > 0);
4851 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4852
4853 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4854 if( nvarsC1 < 2 && nvarsC2 > 0)
4855 {
4856 SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4857 assert(nvarsC1 >= 1);
4858 }
4859 assert(nvarsC2 == 0 || nvarsC1 >= 1);
4860
4861 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4862 * R = { j in N\C : x*_j = 0 } and
4863 * F = (N\C)\F
4864 */
4865 getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4866 assert(nvarsF + nvarsR == nnonmincovervars);
4867 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4868
4869 /* lift cuts without GUB information */
4870 if( gubset == NULL )
4871 {
4872 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4873 * lifting procedure
4874 */
4875 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4876
4877 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4878 *
4879 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j }
4880 *
4881 * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
4882 *
4883 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4884 *
4885 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4886 * up-lifting for the variables in R according to the second level lifting sequence
4887 */
4888 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4889 varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4890 }
4891 /* lift cuts with GUB information */
4892 else
4893 {
4894 int* gubconsGC1;
4895 int* gubconsGC2;
4896 int* gubconsGFC1;
4897 int* gubconsGR;
4898 int ngubconsGC1;
4899 int ngubconsGC2;
4900 int ngubconsGFC1;
4901 int ngubconsGR;
4902 int ngubconss;
4903 int nconstightened;
4904 int maxgubvarssize;
4905
4906 assert(nvars == gubset->nvars);
4907
4908 ngubconsGC1 = 0;
4909 ngubconsGC2 = 0;
4910 ngubconsGFC1 = 0;
4911 ngubconsGR = 0;
4912 ngubconss = gubset->ngubconss;
4913 nconstightened = 0;
4914 maxgubvarssize = 0;
4915
4916 /* allocates temporary memory */
4917 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4918 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4919 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4921
4922 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4923 * the GUBs for the sequential GUB wise lifting procedure
4924 */
4925 SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4926 nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4927 &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4928
4929 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4930 *
4931 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j,
4932 * sum_{j in Q_i} x_j <= 1, forall i in I }
4933 *
4934 * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
4935 *
4936 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0, sum_{j in Q_i} x_j <= 1, forall i in I },
4937 *
4938 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4939 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4940 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4941 */
4942 SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4943 gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4944 MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4945
4946 /* frees temporary memory */
4947 SCIPfreeBufferArray(scip, &gubconsGR);
4948 SCIPfreeBufferArray(scip, &gubconsGFC1);
4949 SCIPfreeBufferArray(scip, &gubconsGC2);
4950 SCIPfreeBufferArray(scip, &gubconsGC1);
4951 }
4952
4953 /* checks if lifting yielded a violated cut */
4954 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4955 {
4956 SCIP_ROW* row;
4957 char name[SCIP_MAXSTRLEN];
4958 int j;
4959
4960 /* creates LP row */
4961 assert( cons == NULL || sepa == NULL );
4962 if ( cons != NULL )
4963 {
4965 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4966 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4967 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4968 }
4969 else if ( sepa != NULL )
4970 {
4971 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4972 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4973 }
4974 else
4975 {
4976 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4978 }
4979
4980 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4982 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4983 for( j = 0; j < nvarsC1; j++ )
4984 {
4985 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4986 }
4987 for( j = 0; j < nvarsC2; j++ )
4988 {
4989 if( liftcoefs[varsC2[j]] > 0 )
4990 {
4991 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4992 }
4993 }
4994 for( j = 0; j < nvarsF; j++ )
4995 {
4996 if( liftcoefs[varsF[j]] > 0 )
4997 {
4998 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4999 }
5000 }
5001 for( j = 0; j < nvarsR; j++ )
5002 {
5003 if( liftcoefs[varsR[j]] > 0 )
5004 {
5005 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5006 }
5007 }
5009
5010 /* checks if cut is violated enough */
5011 if( SCIPisCutEfficacious(scip, sol, row) )
5012 {
5013 if( cons != NULL )
5014 {
5016 }
5018 (*ncuts)++;
5019 }
5020 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5021 }
5022
5023 /* frees temporary memory */
5024 SCIPfreeBufferArray(scip, &liftcoefs);
5025 SCIPfreeBufferArray(scip, &varsR);
5026 SCIPfreeBufferArray(scip, &varsF);
5027 SCIPfreeBufferArray(scip, &varsC2);
5028 SCIPfreeBufferArray(scip, &varsC1);
5029
5030 return SCIP_OKAY;
5031}
5032
5033/** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5034static
5036 SCIP* scip, /**< SCIP data structure */
5037 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5038 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5039 SCIP_VAR** vars, /**< variables in knapsack constraint */
5040 int nvars, /**< number of variables in knapsack constraint */
5041 int ntightened, /**< number of variables with tightened upper bound */
5042 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5043 SCIP_Longint capacity, /**< capacity of knapsack */
5044 SCIP_Real* solvals, /**< solution values of all problem variables */
5045 int* feassetvars, /**< variables in feasible set */
5046 int* nonfeassetvars, /**< variables not in feasible set */
5047 int nfeassetvars, /**< number of variables in feasible set */
5048 int nnonfeassetvars, /**< number of variables not in feasible set */
5049 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5050 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5051 int* ncuts /**< pointer to add up the number of found cuts */
5052 )
5053{
5054 int* varsT1;
5055 int* varsT2;
5056 int* varsF;
5057 int* varsR;
5058 int* liftcoefs;
5059 SCIP_Real cutact;
5060 int nvarsT1;
5061 int nvarsT2;
5062 int nvarsF;
5063 int nvarsR;
5064 int liftrhs;
5065 int j;
5066
5067 assert( cutoff != NULL );
5068 *cutoff = FALSE;
5069
5070 /* allocates temporary memory */
5075 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5076
5077 /* gets partition (T_1,T_2) of T, i.e. T_1 & T_2 = T and T_1 cap T_2 = emptyset, with T_1 not empty; chooses partition
5078 * as follows
5079 * T_2 = { j in T : x*_j = 1 } and
5080 * T_1 = T\T_2
5081 */
5082 getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5083 assert(nvarsT1 + nvarsT2 == nfeassetvars);
5084
5085 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5086 if( nvarsT1 == 0 && nvarsT2 > 0)
5087 {
5088 SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5089 assert(nvarsT1 == 1);
5090 }
5091 assert(nvarsT2 == 0 || nvarsT1 > 0);
5092
5093 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5094 * R = { j in N\T : x*_j = 0 } and
5095 * F = (N\T)\F
5096 */
5097 getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5098 assert(nvarsF + nvarsR == nnonfeassetvars);
5099 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5100
5101 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5102 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5103 * is included in the sorting routine)
5104 */
5105 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5106
5107 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5108 *
5109 * S^0 = { x in {0,1}^|T_1| : sum_{j in T_1} a_j x_j <= a_0 - sum_{j in T_2} a_j }
5110 *
5111 * to a valid inequality sum_{j in T_1} x_j + sum_{j in N\T_1} alpha_j x_j <= |T_1| + sum_{j in T_2} alpha_j for
5112 *
5113 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5114 *
5115 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5116 * up-lifting for the variabels in R according to the second level lifting sequence
5117 */
5118 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5119 nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5120
5121 /* checks if lifting yielded a violated cut */
5122 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5123 {
5124 SCIP_ROW* row;
5125 char name[SCIP_MAXSTRLEN];
5126
5127 /* creates LP row */
5128 assert( cons == NULL || sepa == NULL );
5129 if( cons != NULL )
5130 {
5133 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5134 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5135 }
5136 else if ( sepa != NULL )
5137 {
5138 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5139 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5140 }
5141 else
5142 {
5143 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5145 }
5146
5147 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5149 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5150 for( j = 0; j < nvarsT1; j++ )
5151 {
5152 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5153 }
5154 for( j = 0; j < nvarsT2; j++ )
5155 {
5156 if( liftcoefs[varsT2[j]] > 0 )
5157 {
5158 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5159 }
5160 }
5161 for( j = 0; j < nvarsF; j++ )
5162 {
5163 if( liftcoefs[varsF[j]] > 0 )
5164 {
5165 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5166 }
5167 }
5168 for( j = 0; j < nvarsR; j++ )
5169 {
5170 if( liftcoefs[varsR[j]] > 0 )
5171 {
5172 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5173 }
5174 }
5176
5177 /* checks if cut is violated enough */
5178 if( SCIPisCutEfficacious(scip, sol, row) )
5179 {
5180 if( cons != NULL )
5181 {
5183 }
5185 (*ncuts)++;
5186 }
5187 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5188 }
5189
5190 /* frees temporary memory */
5191 SCIPfreeBufferArray(scip, &liftcoefs);
5192 SCIPfreeBufferArray(scip, &varsR);
5193 SCIPfreeBufferArray(scip, &varsF);
5194 SCIPfreeBufferArray(scip, &varsT2);
5195 SCIPfreeBufferArray(scip, &varsT1);
5196
5197 return SCIP_OKAY;
5198}
5199
5200/** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5201static
5203 SCIP* scip, /**< SCIP data structure */
5204 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5205 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5206 SCIP_VAR** vars, /**< variables in knapsack constraint */
5207 int nvars, /**< number of variables in knapsack constraint */
5208 int ntightened, /**< number of variables with tightened upper bound */
5209 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5210 SCIP_Longint capacity, /**< capacity of knapsack */
5211 SCIP_Real* solvals, /**< solution values of all problem variables */
5212 int* mincovervars, /**< mincover variables */
5213 int* nonmincovervars, /**< nonmincover variables */
5214 int nmincovervars, /**< number of mincover variables */
5215 int nnonmincovervars, /**< number of nonmincover variables */
5216 SCIP_Longint mincoverweight, /**< weight of minimal cover */
5217 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5218 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5219 int* ncuts /**< pointer to add up the number of found cuts */
5220 )
5221{
5222 SCIP_Real* realliftcoefs;
5223 SCIP_Real cutact;
5224 int liftrhs;
5225
5226 assert( cutoff != NULL );
5227 *cutoff = FALSE;
5228 cutact = 0.0;
5229
5230 /* allocates temporary memory */
5231 SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5232
5233 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5234 *
5235 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5236 *
5237 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5238 *
5239 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5240 *
5241 * uses superadditive up-lifting for the variables in N\C.
5242 */
5243 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5244 nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5245 liftrhs = nmincovervars - 1;
5246
5247 /* checks if lifting yielded a violated cut */
5248 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5249 {
5250 SCIP_ROW* row;
5251 char name[SCIP_MAXSTRLEN];
5252 int j;
5253
5254 /* creates LP row */
5255 assert( cons == NULL || sepa == NULL );
5256 if ( cons != NULL )
5257 {
5260 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5261 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5262 }
5263 else if ( sepa != NULL )
5264 {
5265 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5266 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5267 }
5268 else
5269 {
5270 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5272 }
5273
5274 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5276 assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5277 for( j = 0; j < nmincovervars; j++ )
5278 {
5279 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5280 }
5281 for( j = 0; j < nnonmincovervars; j++ )
5282 {
5283 assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5284 if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5285 {
5286 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5287 }
5288 }
5290
5291 /* checks if cut is violated enough */
5292 if( SCIPisCutEfficacious(scip, sol, row) )
5293 {
5294 if( cons != NULL )
5295 {
5297 }
5299 (*ncuts)++;
5300 }
5301 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5302 }
5303
5304 /* frees temporary memory */
5305 SCIPfreeBufferArray(scip, &realliftcoefs);
5306
5307 return SCIP_OKAY;
5308}
5309
5310/** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5311 * to be in C, i.e. in the order of non-increasing (1 - x*_j)/a_j, if the transformed separation problem was used to find
5312 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5313 * note that all variables with x*_j = 1 will be removed last
5314 */
5315static
5317 SCIP* scip, /**< SCIP data structure */
5318 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5319 SCIP_Longint capacity, /**< capacity of knapsack */
5320 SCIP_Real* solvals, /**< solution values of all problem variables */
5321 int* covervars, /**< pointer to store cover variables */
5322 int* noncovervars, /**< pointer to store noncover variables */
5323 int* ncovervars, /**< pointer to store number of cover variables */
5324 int* nnoncovervars, /**< pointer to store number of noncover variables */
5325 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5326 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5327 )
5328{
5329 SORTKEYPAIR** sortkeypairs;
5330 SORTKEYPAIR** sortkeypairssorted;
5331 SCIP_Longint minweight;
5332 int nsortkeypairs;
5333 int minweightidx;
5334 int j;
5335 int k;
5336
5337 assert(scip != NULL);
5338 assert(covervars != NULL);
5339 assert(noncovervars != NULL);
5340 assert(ncovervars != NULL);
5341 assert(*ncovervars > 0);
5342 assert(nnoncovervars != NULL);
5343 assert(*nnoncovervars >= 0);
5344 assert(coverweight != NULL);
5345 assert(*coverweight > 0);
5346 assert(*coverweight > capacity);
5347
5348 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5349 * order */
5350 nsortkeypairs = *ncovervars;
5351 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5352 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5353
5354 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5355 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5356 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5357 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5358 */
5359 assert(*ncovervars == nsortkeypairs);
5360 if( modtransused )
5361 {
5362 for( j = 0; j < *ncovervars; j++ )
5363 {
5364 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5365 sortkeypairssorted[j] = sortkeypairs[j];
5366
5367 sortkeypairs[j]->key1 = solvals[covervars[j]];
5368 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5369 }
5370 }
5371 else
5372 {
5373 for( j = 0; j < *ncovervars; j++ )
5374 {
5375 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5376 sortkeypairssorted[j] = sortkeypairs[j];
5377
5378 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5379 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5380 }
5381 }
5382 SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5383
5384 /* gets j' with a_j' = min{ a_j : j in C } */
5385 minweightidx = 0;
5386 minweight = weights[covervars[minweightidx]];
5387 for( j = 1; j < *ncovervars; j++ )
5388 {
5389 if( weights[covervars[j]] <= minweight )
5390 {
5391 minweightidx = j;
5392 minweight = weights[covervars[minweightidx]];
5393 }
5394 }
5395 assert(minweightidx >= 0 && minweightidx < *ncovervars);
5396 assert(minweight > 0 && minweight <= *coverweight);
5397
5398 j = 0;
5399 /* removes variables from C until the remaining variables form a minimal cover */
5400 while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5401 {
5402 assert(minweightidx >= j);
5403 assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5404
5405 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5406 if( (*coverweight) - weights[covervars[j]] <= capacity )
5407 {
5408 ++j;
5409 continue;
5410 }
5411
5412 /* adds j to N\C */
5413 noncovervars[*nnoncovervars] = covervars[j];
5414 (*nnoncovervars)++;
5415
5416 /* removes j from C */
5417 (*coverweight) -= weights[covervars[j]];
5418 for( k = j; k < (*ncovervars) - 1; k++ )
5419 covervars[k] = covervars[k+1];
5420 (*ncovervars)--;
5421
5422 /* updates j' with a_j' = min{ a_j : j in C } */
5423 if( j == minweightidx )
5424 {
5425 minweightidx = 0;
5426 minweight = weights[covervars[minweightidx]];
5427 for( k = 1; k < *ncovervars; k++ )
5428 {
5429 if( weights[covervars[k]] <= minweight )
5430 {
5431 minweightidx = k;
5432 minweight = weights[covervars[minweightidx]];
5433 }
5434 }
5435 assert(minweight > 0 && minweight <= *coverweight);
5436 assert(minweightidx >= 0 && minweightidx < *ncovervars);
5437 }
5438 else
5439 {
5440 assert(minweightidx > j);
5441 minweightidx--;
5442 }
5443 /* j needs to stay the same */
5444 }
5445 assert((*coverweight) > capacity);
5446 assert((*coverweight) - minweight <= capacity);
5447
5448 /* frees temporary memory */
5449 for( j = nsortkeypairs-1; j >= 0; j-- )
5450 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5451 SCIPfreeBufferArray(scip, &sortkeypairssorted);
5452 SCIPfreeBufferArray(scip, &sortkeypairs);
5453
5454 return SCIP_OKAY;
5455}
5456
5457/** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5458 * they were chosen to be in C_init:
5459 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5460 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5461 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5462 * and all subsequent feasible sets.
5463 */
5464static
5466 SCIP* scip, /**< SCIP data structure */
5467 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5468 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5469 SCIP_VAR** vars, /**< variables in knapsack constraint */
5470 int nvars, /**< number of variables in knapsack constraint */
5471 int ntightened, /**< number of variables with tightened upper bound */
5472 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5473 SCIP_Longint capacity, /**< capacity of knapsack */
5474 SCIP_Real* solvals, /**< solution values of all problem variables */
5475 int* covervars, /**< pointer to store cover variables */
5476 int* noncovervars, /**< pointer to store noncover variables */
5477 int* ncovervars, /**< pointer to store number of cover variables */
5478 int* nnoncovervars, /**< pointer to store number of noncover variables */
5479 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5480 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5481 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5482 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5483 int* ncuts /**< pointer to add up the number of found cuts */
5484 )
5485{
5486 SCIP_Real* sortkeys;
5487 int j;
5488 int k;
5489
5490 assert(scip != NULL);
5491 assert(covervars != NULL);
5492 assert(noncovervars != NULL);
5493 assert(ncovervars != NULL);
5494 assert(*ncovervars > 0);
5495 assert(nnoncovervars != NULL);
5496 assert(*nnoncovervars >= 0);
5497 assert(coverweight != NULL);
5498 assert(*coverweight > 0);
5499 assert(*coverweight > capacity);
5500 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5501 assert(cutoff != NULL);
5502
5503 *cutoff = FALSE;
5504
5505 /* allocates temporary memory */
5506 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5507
5508 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5509 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5510 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5511 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5512 */
5513 if( modtransused )
5514 {
5515 for( j = 0; j < *ncovervars; j++ )
5516 {
5517 sortkeys[j] = solvals[covervars[j]];
5518 assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5519 }
5520 }
5521 else
5522 {
5523 for( j = 0; j < *ncovervars; j++ )
5524 {
5525 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5526 assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5527 }
5528 }
5529 SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5530
5531 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5532 * in addition to an extended weight inequality this gives cardinality inequalities */
5533 while( *ncovervars >= 2 )
5534 {
5535 /* adds first element of C_init to N\C_init */
5536 noncovervars[*nnoncovervars] = covervars[0];
5537 (*nnoncovervars)++;
5538
5539 /* removes first element from C_init */
5540 (*coverweight) -= weights[covervars[0]];
5541 for( k = 0; k < (*ncovervars) - 1; k++ )
5542 covervars[k] = covervars[k+1];
5543 (*ncovervars)--;
5544
5545 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5546 if( (*coverweight) <= capacity )
5547 {
5548 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5549 covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5550 }
5551
5552 /* stop if cover is too large */
5553 if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5554 break;
5555 }
5556
5557 /* frees temporary memory */
5558 SCIPfreeBufferArray(scip, &sortkeys);
5559
5560 return SCIP_OKAY;
5561}
5562
5563/** separates different classes of valid inequalities for the 0-1 knapsack problem */
5565 SCIP* scip, /**< SCIP data structure */
5566 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5567 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5568 SCIP_VAR** vars, /**< variables in knapsack constraint */
5569 int nvars, /**< number of variables in knapsack constraint */
5570 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5571 SCIP_Longint capacity, /**< capacity of knapsack */
5572 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5573 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5574 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5575 int* ncuts /**< pointer to add up the number of found cuts */
5576 )
5577{
5578 SCIP_Real* solvals;
5579 int* covervars;
5580 int* noncovervars;
5581 SCIP_Bool coverfound;
5582 SCIP_Bool fractional;
5583 SCIP_Bool modtransused;
5584 SCIP_Longint coverweight;
5585 int ncovervars;
5586 int nnoncovervars;
5587 int ntightened;
5588
5589 assert(scip != NULL);
5590 assert(capacity >= 0);
5591 assert(cutoff != NULL);
5592 assert(ncuts != NULL);
5593
5594 *cutoff = FALSE;
5595
5596 if( nvars == 0 )
5597 return SCIP_OKAY;
5598
5599 assert(vars != NULL);
5600 assert(nvars > 0);
5601 assert(weights != NULL);
5602
5603 /* increase age of constraint (age is reset to zero, if a cut was found) */
5604 if( cons != NULL )
5605 {
5606 SCIP_CALL( SCIPincConsAge(scip, cons) );
5607 }
5608
5609 /* allocates temporary memory */
5611 SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5612 SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5613
5614 /* gets solution values of all problem variables */
5615 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5616
5617#ifdef SCIP_DEBUG
5618 {
5619 int i;
5620
5621 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5622 cons == NULL ? "-" : SCIPconsGetName(cons));
5623 for( i = 0; i < nvars; ++i )
5624 {
5625 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5626 }
5627 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5628 }
5629#endif
5630
5631 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5632 */
5633 if( usegubs )
5634 {
5635 SCIP_GUBSET* gubset;
5636
5637 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5638
5639 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5640 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5641
5642 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5643 SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5644 assert(gubset->ngubconss <= nvars);
5645
5646 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5647 * MODIFIED transformed separation problem and taking into account the following fixing:
5648 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5649 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5650 * if one exists
5651 */
5652 modtransused = TRUE;
5653 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5654 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5655
5656 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5657
5658 /* if x* is not fractional we stop the separation routine */
5659 if( !fractional )
5660 {
5661 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5662
5663 /* frees memory for GUB set data structure */
5664 GUBsetFree(scip, &gubset);
5665
5666 goto TERMINATE;
5667 }
5668
5669 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5670 if( coverfound )
5671 {
5672 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5673 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5674 */
5675 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5676 &nnoncovervars, &coverweight, modtransused) );
5677
5678 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5679 if( gubset->ngubconss < nvars )
5680 {
5681 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5682 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5683 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5684 }
5685 else
5686 {
5687 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5688 * GUB information
5689 */
5690 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5691 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5692 }
5693 }
5694
5695 /* frees memory for GUB set data structure */
5696 GUBsetFree(scip, &gubset);
5697 }
5698 else
5699 {
5700 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5701 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5702 */
5703
5704 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5705 * MODIFIED transformed separation problem and taking into account the following fixing:
5706 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5707 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5708 * if one exists
5709 */
5710 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5711 modtransused = TRUE;
5712 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5713 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5714 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5715
5716 /* if x* is not fractional we stop the separation routine */
5717 if( !fractional )
5718 goto TERMINATE;
5719
5720 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5721 if( coverfound )
5722 {
5723 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5724 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5725 */
5726 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5727 &nnoncovervars, &coverweight, modtransused) );
5728
5729 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5730 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5731 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5732
5733 if( USESUPADDLIFT ) /*lint !e506 !e774*/
5734 {
5735 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5736 /* separates lifted minimal cover inequalities using superadditive up-lifting */
5737 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5738 solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5739 }
5740 }
5741 }
5742
5743 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5744 if ( ! (*cutoff) )
5745 {
5746 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5747 * transformed separation problem and taking into account the following fixing:
5748 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5749 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5750 * if one exists
5751 */
5752 SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5753 modtransused = FALSE;
5754 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5755 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5756 assert(fractional);
5757 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5758
5759 /* if no cover was found we stop the separation routine */
5760 if( coverfound )
5761 {
5762 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5763 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5764 * up- and down-lifting for this feasible set and all subsequent feasible sets.
5765 */
5766 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5767 &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5768 }
5769 }
5770
5771 TERMINATE:
5772 /* frees temporary memory */
5773 SCIPfreeBufferArray(scip, &noncovervars);
5774 SCIPfreeBufferArray(scip, &covervars);
5775 SCIPfreeBufferArray(scip, &solvals);
5776
5777 return SCIP_OKAY;
5778}
5779
5780/* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5782 SCIP* scip, /**< SCIP data structure */
5783 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5784 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5785 int nknapvars, /**< number of variables in the continuous knapsack constraint */
5786 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5787 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5788 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5789 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5790 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5791 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5792 int* ncuts /**< pointer to add up the number of found cuts */
5793 )
5794{
5795 SCIP_VAR** binvars;
5796 SCIP_VAR** consvars;
5797 SCIP_Real* binvals;
5798 SCIP_Longint* consvals;
5799 SCIP_Longint minact;
5800 SCIP_Longint maxact;
5801 SCIP_Real intscalar;
5802 SCIP_Bool success;
5803 int nbinvars;
5804 int nconsvars;
5805 int i;
5806
5807 int* tmpindices;
5808 int tmp;
5809 SCIP_CONSHDLR* conshdlr;
5810 SCIP_CONSHDLRDATA* conshdlrdata;
5811 SCIP_Bool noknapsackconshdlr;
5812 SCIP_Bool usegubs;
5813
5814 assert(nknapvars > 0);
5815 assert(knapvars != NULL);
5816 assert(cutoff != NULL);
5817
5818 tmpindices = NULL;
5819
5820 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5821 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5822
5823 binvars = SCIPgetVars(scip);
5824
5825 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5826 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5827
5828 *cutoff = FALSE;
5829
5830 if( nbinvars == 0 )
5831 return SCIP_OKAY;
5832
5833 /* set up data structures */
5834 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5835 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5836
5837 /* get conshdlrdata to use cleared memory */
5838 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5839 if( conshdlr == NULL )
5840 {
5841 noknapsackconshdlr = TRUE;
5842 usegubs = DEFAULT_USEGUBS;
5843
5844 SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5845 BMSclearMemoryArray(binvals, nbinvars);
5846 }
5847 else
5848 {
5849 noknapsackconshdlr = FALSE;
5850 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5851 assert(conshdlrdata != NULL);
5852 usegubs = conshdlrdata->usegubs;
5853
5854 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5855
5856 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5857 * change their types to SCIP_VARTYPE_BINARY during presolving
5858 */
5859 if( conshdlrdata->reals1size == 0 )
5860 {
5861 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5862 conshdlrdata->reals1size = 1;
5863 conshdlrdata->reals1[0] = 0.0;
5864 }
5865
5866 assert(conshdlrdata->reals1size > 0);
5867
5868 /* next if condition should normally not be true, because it means that presolving has created more binary
5869 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5870 * transform all integers into their binary representation then it maybe happens
5871 */
5872 if( conshdlrdata->reals1size < nbinvars )
5873 {
5874 int oldsize = conshdlrdata->reals1size;
5875
5876 conshdlrdata->reals1size = nbinvars;
5877 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5878 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5879 }
5880 binvals = conshdlrdata->reals1;
5881
5882 /* check for cleared array, all entries have to be zero */
5883#ifndef NDEBUG
5884 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5885 {
5886 assert(binvals[tmp] == 0);
5887 }
5888#endif
5889 }
5890
5891 tmp = 0;
5892
5893 /* relax continuous knapsack constraint:
5894 * 1. make all variables binary:
5895 * if x_j is continuous or integer variable substitute:
5896 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5897 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5898 * 2. convert coefficients of all variables to positive integers:
5899 * - scale all coefficients a_j to a~_j integral
5900 * - substitute x~_j = 1 - x_j if a~_j < 0
5901 */
5902
5903 /* replace integer and continuous variables with binary variables */
5904 for( i = 0; i < nknapvars; i++ )
5905 {
5906 SCIP_VAR* var;
5907
5908 var = knapvars[i];
5909
5911 {
5912 SCIP_Real solval;
5914
5915 solval = SCIPgetSolVal(scip, sol, var);
5916
5917 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5918 if( SCIPisFeasLT(scip, solval, 0.0 )
5919 || SCIPisFeasGT(scip, solval, 1.0) )
5920 {
5921 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5922 solval, SCIPvarGetName(var));
5923 goto TERMINATE;
5924 }
5925
5926 binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5927 if( !noknapsackconshdlr )
5928 {
5929 assert(tmpindices != NULL);
5930
5931 tmpindices[tmp] = SCIPvarGetProbindex(var);
5932 ++tmp;
5933 }
5934 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5935 }
5936 else if( valscale * knapvals[i] > 0.0 )
5937 {
5938 SCIP_VAR** zvlb;
5939 SCIP_Real* bvlb;
5940 SCIP_Real* dvlb;
5941 SCIP_Real bestlbsol;
5942 int bestlbtype;
5943 int nvlb;
5944 int j;
5945
5946 /* a_j > 0: substitution with lb or vlb */
5947 nvlb = SCIPvarGetNVlbs(var);
5948 zvlb = SCIPvarGetVlbVars(var);
5949 bvlb = SCIPvarGetVlbCoefs(var);
5951
5952 /* search for lb or vlb with maximal bound value */
5953 bestlbsol = SCIPvarGetLbGlobal(var);
5954 bestlbtype = -1;
5955 for( j = 0; j < nvlb; j++ )
5956 {
5957 /* use only numerical stable vlb with binary variable z */
5958 if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5959 {
5960 SCIP_Real vlbsol;
5961
5962 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5963 (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5964 {
5965 *cutoff = TRUE;
5966 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5968 bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5969 goto TERMINATE;
5970 }
5971
5972 assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5973 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5974 if( SCIPisGE(scip, vlbsol, bestlbsol) )
5975 {
5976 bestlbsol = vlbsol;
5977 bestlbtype = j;
5978 }
5979 }
5980 }
5981
5982 /* if no lb or vlb with binary variable was found, we have to abort */
5983 if( SCIPisInfinity(scip, -bestlbsol) )
5984 goto TERMINATE;
5985
5986 if( bestlbtype == -1 )
5987 {
5988 rhs -= valscale * knapvals[i] * bestlbsol;
5989 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5990 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5991 }
5992 else
5993 {
5994 assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5995 rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5996 binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5997
5998 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5999 goto TERMINATE;
6000
6001 if( !noknapsackconshdlr )
6002 {
6003 assert(tmpindices != NULL);
6004
6005 tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
6006 ++tmp;
6007 }
6008 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6009 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6010 bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
6011 SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
6012 }
6013 }
6014 else
6015 {
6016 SCIP_VAR** zvub;
6017 SCIP_Real* bvub;
6018 SCIP_Real* dvub;
6019 SCIP_Real bestubsol;
6020 int bestubtype;
6021 int nvub;
6022 int j;
6023
6024 assert(valscale * knapvals[i] < 0.0);
6025
6026 /* a_j < 0: substitution with ub or vub */
6027 nvub = SCIPvarGetNVubs(var);
6028 zvub = SCIPvarGetVubVars(var);
6029 bvub = SCIPvarGetVubCoefs(var);
6031
6032 /* search for ub or vub with minimal bound value */
6033 bestubsol = SCIPvarGetUbGlobal(var);
6034 bestubtype = -1;
6035 for( j = 0; j < nvub; j++ )
6036 {
6037 /* use only numerical stable vub with active binary variable z */
6038 if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6039 {
6040 SCIP_Real vubsol;
6041
6042 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6043 (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6044 {
6045 *cutoff = TRUE;
6046 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6048 bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6049 goto TERMINATE;
6050 }
6051
6052 assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6053 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6054 if( SCIPisLE(scip, vubsol, bestubsol) )
6055 {
6056 bestubsol = vubsol;
6057 bestubtype = j;
6058 }
6059 }
6060 }
6061
6062 /* if no ub or vub with binary variable was found, we have to abort */
6063 if( SCIPisInfinity(scip, bestubsol) )
6064 goto TERMINATE;
6065
6066 if( bestubtype == -1 )
6067 {
6068 rhs -= valscale * knapvals[i] * bestubsol;
6069 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6070 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6071 }
6072 else
6073 {
6074 assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6075 rhs -= valscale * knapvals[i] * dvub[bestubtype];
6076 binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6077
6078 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6079 goto TERMINATE;
6080
6081 if( !noknapsackconshdlr )
6082 {
6083 assert(tmpindices != NULL);
6084
6085 tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6086 ++tmp;
6087 }
6088 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6089 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6090 bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6091 SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6092 }
6093 }
6094 }
6095
6096 /* convert coefficients of all (now binary) variables to positive integers:
6097 * - make all coefficients integral
6098 * - make all coefficients positive (substitute negated variable)
6099 */
6100 nconsvars = 0;
6101
6102 /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6103 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6104 */
6106 KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6107 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6108
6109 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6110 if( !success )
6111 intscalar = 1.0;
6112
6113 /* make all coefficients integral and positive:
6114 * - scale a~_j = a_j * intscalar
6115 * - substitute x~_j = 1 - x_j if a~_j < 0
6116 */
6117 rhs = rhs * intscalar;
6118
6119 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6120 minact = 0;
6121 maxact = 0;
6122 for( i = 0; i < nbinvars; i++ )
6123 {
6124 SCIP_VAR* var;
6125 SCIP_Longint val;
6126
6127 val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6128 if( val == 0 )
6129 continue;
6130
6131 if( val > 0 )
6132 {
6133 var = binvars[i];
6134 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6135 val, SCIPvarGetName(var), binvals[i], rhs);
6136 }
6137 else
6138 {
6139 assert(val < 0);
6140
6141 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6142 val = -val; /*lint !e2704*/
6143 rhs += val;
6144 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6145 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6146 }
6147
6148 if( SCIPvarGetLbLocal(var) > 0.5 )
6149 minact += val;
6150 if( SCIPvarGetUbLocal(var) > 0.5 )
6151 maxact += val;
6152 consvals[nconsvars] = val;
6153 consvars[nconsvars] = var;
6154 nconsvars++;
6155 }
6156
6157 if( nconsvars > 0 )
6158 {
6159 SCIP_Longint capacity;
6160
6161 assert(consvars != NULL);
6162 assert(consvals != NULL);
6163 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6164
6165#ifdef SCIP_DEBUG
6166 {
6167 SCIP_Real act;
6168
6169 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6170 act = 0.0;
6171 for( i = 0; i < nconsvars; ++i )
6172 {
6173 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6174 SCIPgetSolVal(scip, sol, consvars[i]));
6175 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6176 }
6177 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6178 capacity, rhs, act, minact, maxact);
6179 }
6180#endif
6181
6182 if( minact > capacity )
6183 {
6184 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6185 *cutoff = TRUE;
6186 goto TERMINATE;
6187 }
6188
6189 if( maxact > capacity )
6190 {
6191 /* separate lifted cut from relaxed knapsack constraint */
6192 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6193 }
6194 }
6195
6196 TERMINATE:
6197 /* free data structures */
6198 if( noknapsackconshdlr)
6199 {
6200 SCIPfreeBufferArray(scip, &binvals);
6201 }
6202 else
6203 {
6204 /* clear binvals */
6205 for( --tmp; tmp >= 0; --tmp)
6206 {
6207 assert(tmpindices != NULL);
6208 binvals[tmpindices[tmp]] = 0;
6209 }
6210 SCIPfreeBufferArray(scip, &tmpindices);
6211 }
6212 SCIPfreeBufferArray(scip, &consvals);
6213 SCIPfreeBufferArray(scip, &consvars);
6214
6215 return SCIP_OKAY;
6216}
6217
6218/** separates given knapsack constraint */
6219static
6221 SCIP* scip, /**< SCIP data structure */
6222 SCIP_CONS* cons, /**< knapsack constraint */
6223 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6224 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6225 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6226 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6227 int* ncuts /**< pointer to add up the number of found cuts */
6228 )
6229{
6230 SCIP_CONSDATA* consdata;
6231 SCIP_Bool violated;
6232
6233 assert(ncuts != NULL);
6234 assert(cutoff != NULL);
6235 *cutoff = FALSE;
6236
6237 consdata = SCIPconsGetData(cons);
6238 assert(consdata != NULL);
6239
6240 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6241
6242 /* check knapsack constraint itself for feasibility */
6243 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6244
6245 if( violated )
6246 {
6247 /* add knapsack constraint as LP row to the LP */
6249 (*ncuts)++;
6250 }
6251 else if( sepacuts )
6252 {
6253 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6254 consdata->capacity, sol, usegubs, cutoff, ncuts) );
6255 }
6256
6257 return SCIP_OKAY;
6258}
6259
6260/** adds coefficient to constraint data */
6261static
6263 SCIP* scip, /**< SCIP data structure */
6264 SCIP_CONS* cons, /**< knapsack constraint */
6265 SCIP_VAR* var, /**< variable to add to knapsack */
6266 SCIP_Longint weight /**< weight of variable in knapsack */
6267 )
6268{
6269 SCIP_CONSDATA* consdata;
6270
6271 consdata = SCIPconsGetData(cons);
6272 assert(consdata != NULL);
6274 assert(weight > 0);
6275
6276 /* add the new coefficient to the LP row */
6277 if( consdata->row != NULL )
6278 {
6279 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6280 }
6281
6282 /* check for fixed variable */
6283 if( SCIPvarGetLbGlobal(var) > 0.5 )
6284 {
6285 /* variable is fixed to one: reduce capacity */
6286 consdata->capacity -= weight;
6287 }
6288 else if( SCIPvarGetUbGlobal(var) > 0.5 )
6289 {
6290 SCIP_Bool negated;
6291
6292 /* get binary representative of variable */
6294
6295 /* insert coefficient */
6296 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6297 consdata->vars[consdata->nvars] = var;
6298 consdata->weights[consdata->nvars] = weight;
6299 consdata->nvars++;
6300
6301 /* capture variable */
6303
6304 /* install the rounding locks of variable */
6305 SCIP_CALL( lockRounding(scip, cons, var) );
6306
6307 /* catch events */
6308 if( SCIPconsIsTransformed(cons) )
6309 {
6310 SCIP_CONSHDLRDATA* conshdlrdata;
6311
6312 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6313 assert(conshdlrdata != NULL);
6314 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6316 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6317 &consdata->eventdata[consdata->nvars-1]->filterpos) );
6318
6319 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6320 consdata->existmultaggr = TRUE;
6321
6322 /* mark constraint to be propagated and presolved */
6324 consdata->presolvedtiming = 0;
6325 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6326 }
6327
6328 /* update weight sums */
6329 updateWeightSums(consdata, var, weight);
6330
6331 consdata->sorted = FALSE;
6332 consdata->cliquepartitioned = FALSE;
6333 consdata->negcliquepartitioned = FALSE;
6334 consdata->merged = FALSE;
6335 }
6336
6337 return SCIP_OKAY;
6338}
6339
6340/** deletes coefficient at given position from constraint data */
6341static
6343 SCIP* scip, /**< SCIP data structure */
6344 SCIP_CONS* cons, /**< knapsack constraint */
6345 int pos /**< position of coefficient to delete */
6346 )
6347{
6348 SCIP_CONSDATA* consdata;
6349 SCIP_VAR* var;
6350
6351 consdata = SCIPconsGetData(cons);
6352 assert(consdata != NULL);
6353 assert(0 <= pos && pos < consdata->nvars);
6354
6355 var = consdata->vars[pos];
6356 assert(var != NULL);
6358
6359 /* delete the coefficient from the LP row */
6360 if( consdata->row != NULL )
6361 {
6362 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6363 }
6364
6365 /* remove the rounding locks of variable */
6366 SCIP_CALL( unlockRounding(scip, cons, var) );
6367
6368 /* drop events and mark constraint to be propagated and presolved */
6369 if( SCIPconsIsTransformed(cons) )
6370 {
6371 SCIP_CONSHDLRDATA* conshdlrdata;
6372
6373 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6374 assert(conshdlrdata != NULL);
6376 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6377 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6378
6380 consdata->presolvedtiming = 0;
6381 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6382 }
6383
6384 /* decrease weight sums */
6385 updateWeightSums(consdata, var, -consdata->weights[pos]);
6386
6387 /* move the last variable to the free slot */
6388 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6389 consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6390 if( consdata->eventdata != NULL )
6391 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6392
6393 /* release variable */
6395
6396 /* try to use old clique partitions */
6397 if( consdata->cliquepartitioned )
6398 {
6399 assert(consdata->cliquepartition != NULL);
6400 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6401 * change the clique number */
6402 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6403 {
6404 int oldcliqenum;
6405
6406 oldcliqenum = consdata->cliquepartition[pos];
6407 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6408
6409 /* the following if and else cases assure that we have increasing clique numbers */
6410 if( consdata->cliquepartition[pos] > pos )
6411 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6412 else
6413 {
6414 int i;
6415 int cliquenumbefore;
6416
6417 /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6418 * occurs the same as the old one is still in the cliquepartition */
6419 if( oldcliqenum > consdata->cliquepartition[pos] )
6420 {
6421 for( i = 0; i < consdata->nvars; ++i )
6422 if( oldcliqenum == consdata->cliquepartition[i] )
6423 break;
6424 else if( oldcliqenum < consdata->cliquepartition[i] )
6425 {
6426 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6427 break;
6428 }
6429 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6430 * the biggest index, so decrease the number of cliques
6431 */
6432 if( i == consdata->nvars )
6433 --(consdata->ncliques);
6434 }
6435 /* if the old clique number was smaller than the new one we have to check the front for an element with
6436 * clique number minus 1 */
6437 else if( oldcliqenum < consdata->cliquepartition[pos] )
6438 {
6439 cliquenumbefore = consdata->cliquepartition[pos] - 1;
6440 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6441
6442 if( i < cliquenumbefore )
6443 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6444 }
6445 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6446 else if( pos == consdata->nvars - 1)
6447 {
6448 cliquenumbefore = consdata->cliquepartition[pos];
6449 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6450
6451 if( i < cliquenumbefore )
6452 --(consdata->ncliques);
6453 }
6454 /* if the old clique number is equal to the new one the cliquepartition should be ok */
6455 }
6456 }
6457 else
6458 --(consdata->ncliques);
6459 }
6460
6461 if( consdata->negcliquepartitioned )
6462 {
6463 assert(consdata->negcliquepartition != NULL);
6464 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6465 * change the clique number */
6466 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6467 {
6468 int oldcliqenum;
6469
6470 oldcliqenum = consdata->negcliquepartition[pos];
6471 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6472
6473 /* the following if and else cases assure that we have increasing clique numbers */
6474 if( consdata->negcliquepartition[pos] > pos )
6475 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6476 else
6477 {
6478 int i;
6479 int cliquenumbefore;
6480
6481 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6482 * occurs, the same as the old one occurs */
6483 if( oldcliqenum > consdata->negcliquepartition[pos] )
6484 {
6485 for( i = 0; i < consdata->nvars; ++i )
6486 if( oldcliqenum == consdata->negcliquepartition[i] )
6487 break;
6488 else if( oldcliqenum < consdata->negcliquepartition[i] )
6489 {
6490 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6491 break;
6492 }
6493 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6494 * the biggest index, so decrease the number of negated cliques
6495 */
6496 if( i == consdata->nvars )
6497 --(consdata->nnegcliques);
6498 }
6499 /* if the old clique number was smaller than the new one we have to check the front for an element with
6500 * clique number minus 1 */
6501 else if( oldcliqenum < consdata->negcliquepartition[pos] )
6502 {
6503 cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6504 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6505
6506 if( i < cliquenumbefore )
6507 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6508 }
6509 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6510 else if( pos == consdata->nvars - 1)
6511 {
6512 cliquenumbefore = consdata->negcliquepartition[pos];
6513 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6514
6515 if( i < cliquenumbefore )
6516 --(consdata->nnegcliques);
6517 }
6518 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6519 }
6520 }
6521 else
6522 --(consdata->nnegcliques);
6523 }
6524
6525 --(consdata->nvars);
6526
6527 return SCIP_OKAY;
6528}
6529
6530/** removes all items with weight zero from knapsack constraint */
6531static
6533 SCIP* scip, /**< SCIP data structure */
6534 SCIP_CONS* cons /**< knapsack constraint */
6535 )
6536{
6537 SCIP_CONSDATA* consdata;
6538 int v;
6539
6540 consdata = SCIPconsGetData(cons);
6541 assert(consdata != NULL);
6542
6543 for( v = consdata->nvars-1; v >= 0; --v )
6544 {
6545 if( consdata->weights[v] == 0 )
6546 {
6547 SCIP_CALL( delCoefPos(scip, cons, v) );
6548 }
6549 }
6550
6551 return SCIP_OKAY;
6552}
6553
6554/* perform deletion of variables in all constraints of the constraint handler */
6555static
6557 SCIP* scip, /**< SCIP data structure */
6558 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6559 SCIP_CONS** conss, /**< array of constraints */
6560 int nconss /**< number of constraints */
6561 )
6562{
6563 SCIP_CONSDATA* consdata;
6564 int i;
6565 int v;
6566
6567 assert(scip != NULL);
6568 assert(conshdlr != NULL);
6569 assert(conss != NULL);
6570 assert(nconss >= 0);
6571 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6572
6573 /* iterate over all constraints */
6574 for( i = 0; i < nconss; i++ )
6575 {
6576 consdata = SCIPconsGetData(conss[i]);
6577
6578 /* constraint is marked, that some of its variables were deleted */
6579 if( consdata->varsdeleted )
6580 {
6581 /* iterate over all variables of the constraint and delete them from the constraint */
6582 for( v = consdata->nvars - 1; v >= 0; --v )
6583 {
6584 if( SCIPvarIsDeleted(consdata->vars[v]) )
6585 {
6586 SCIP_CALL( delCoefPos(scip, conss[i], v) );
6587 }
6588 }
6589 consdata->varsdeleted = FALSE;
6590 }
6591 }
6592
6593 return SCIP_OKAY;
6594}
6595
6596/** replaces multiple occurrences of a variable or its negation by a single coefficient */
6597static
6599 SCIP* scip, /**< SCIP data structure */
6600 SCIP_CONS* cons, /**< knapsack constraint */
6601 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6602 )
6603{
6604 SCIP_CONSDATA* consdata;
6605 int v;
6606 int prev;
6607
6608 assert(scip != NULL);
6609 assert(cons != NULL);
6610 assert(cutoff != NULL);
6611
6612 consdata = SCIPconsGetData(cons);
6613 assert(consdata != NULL);
6614
6615 *cutoff = FALSE;
6616
6617 if( consdata->merged )
6618 return SCIP_OKAY;
6619
6620 if( consdata->nvars <= 1 )
6621 {
6622 consdata->merged = TRUE;
6623 return SCIP_OKAY;
6624 }
6625
6626 assert(consdata->vars != NULL || consdata->nvars == 0);
6627
6628 /* sorting array after indices of variables, that's only for faster merging */
6629 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6630 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6631
6632 /* knapsack-sorting (decreasing weights) now lost */
6633 consdata->sorted = FALSE;
6634
6635 v = consdata->nvars - 1;
6636 prev = v - 1;
6637 /* loop backwards through the items: deletion only affects rear items */
6638 while( prev >= 0 )
6639 {
6640 SCIP_VAR* var1;
6641 SCIP_VAR* var2;
6642 SCIP_Bool negated1;
6643 SCIP_Bool negated2;
6644
6645 negated1 = FALSE;
6646 negated2 = FALSE;
6647
6648 var1 = consdata->vars[v];
6649 assert(SCIPvarIsBinary(var1));
6652 {
6653 var1 = SCIPvarGetNegatedVar(var1);
6654 negated1 = TRUE;
6655 }
6656 assert(var1 != NULL);
6657
6658 var2 = consdata->vars[prev];
6659 assert(SCIPvarIsBinary(var2));
6662 {
6663 var2 = SCIPvarGetNegatedVar(var2);
6664 negated2 = TRUE;
6665 }
6666 assert(var2 != NULL);
6667
6668 if( var1 == var2 )
6669 {
6670 /* both variables are either active or negated */
6671 if( negated1 == negated2 )
6672 {
6673 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6674 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6675 SCIP_CALL( delCoefPos(scip, cons, v) );
6676 }
6677 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6678 * and delete item of smaller weight
6679 */
6680 else if( consdata->weights[v] == consdata->weights[prev] )
6681 {
6682 /* both variables eliminate themselves: w*x + w*(1-x) == w */
6683 consdata->capacity -= consdata->weights[v];
6684 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6685 SCIP_CALL( delCoefPos(scip, cons, prev) );
6686
6687 --prev;
6688 }
6689 else if( consdata->weights[v] < consdata->weights[prev] )
6690 {
6691 consdata->capacity -= consdata->weights[v];
6692 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6693 assert(consdata->weights[prev] > 0);
6694 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6695 }
6696 else
6697 {
6698 consdata->capacity -= consdata->weights[prev];
6699 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6700 assert(consdata->weights[v] > 0);
6701 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6702 /* restore order iff necessary */
6703 if( consdata->nvars != v ) /* otherwise the order still stands */
6704 {
6705 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6706 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6707 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6708 --prev;
6709 else /* we need to let v at the same position*/
6710 {
6711 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6712 /* don't decrease v, the same variable may exist up front */
6713 --prev;
6714 continue;
6715 }
6716 }
6717 }
6718 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6719 }
6720 v = prev;
6721 --prev;
6722 }
6723
6724 consdata->merged = TRUE;
6725
6726 /* check infeasibility */
6727 if( consdata->onesweightsum > consdata->capacity )
6728 {
6729 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6730 *cutoff = TRUE;
6731 return SCIP_OKAY;
6732 }
6733
6734 return SCIP_OKAY;
6735}
6736
6737/** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6738 * fixings (dual reductions)
6739 */
6740static
6742 SCIP* scip, /**< SCIP data structure */
6743 SCIP_CONS* cons, /**< knapsack constraint */
6744 int* nfixedvars, /**< pointer to count number of fixings */
6745 int* ndelconss, /**< pointer to count number of deleted constraints */
6746 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6747 )
6748{
6749 SCIP_CONSDATA* consdata;
6750 SCIP_VAR** vars;
6751 SCIP_Real* profits;
6752 int* solitems;
6753 int* nonsolitems;
6754 int* items;
6755 SCIP_Real solval;
6756 SCIP_Bool infeasible;
6757 SCIP_Bool tightened;
6758 SCIP_Bool applicable;
6759 int nsolitems;
6760 int nnonsolitems;
6761 int nvars;
6762 int v;
6763
6765
6766 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6767 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6768 * added to the problems have the check flag set to FALSE
6769 */
6770 if( !SCIPconsIsChecked(cons) )
6771 return SCIP_OKAY;
6772
6773 consdata = SCIPconsGetData(cons);
6774 assert(consdata != NULL);
6775
6776 nvars = consdata->nvars;
6777 vars = consdata->vars;
6778
6781 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6782 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6783
6784 applicable = TRUE;
6785
6786 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6787 * collect object values which are the profits of the knapsack problem
6788 */
6789 for( v = 0; v < nvars; ++v )
6790 {
6791 SCIP_VAR* var;
6792 SCIP_Bool negated;
6793
6794 var = vars[v];
6795 assert(var != NULL);
6796
6797 /* the variable should not be (globally) fixed */
6799
6802 {
6803 applicable = FALSE;
6804 break;
6805 }
6806
6807 negated = FALSE;
6808
6809 /* get the active variable */
6810 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6812
6813 if( negated )
6814 profits[v] = SCIPvarGetObj(var);
6815 else
6816 profits[v] = -SCIPvarGetObj(var);
6817
6818 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6819 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6820 items[v] = v;
6821 }
6822
6823 if( applicable )
6824 {
6825 SCIP_Bool success;
6826
6827 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6829
6830 /* solve knapsack problem exactly */
6831 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6832 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6833
6834 if( success )
6835 {
6836 SCIP_VAR* var;
6837
6838 /* apply solution of the knapsack as dual reductions */
6839 for( v = 0; v < nsolitems; ++v )
6840 {
6841 var = vars[solitems[v]];
6842 assert(var != NULL);
6843
6844 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6846 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6847 assert(!infeasible);
6848 assert(tightened);
6849 (*nfixedvars)++;
6850 }
6851
6852 for( v = 0; v < nnonsolitems; ++v )
6853 {
6854 var = vars[nonsolitems[v]];
6855 assert(var != NULL);
6856
6857 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6859 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6860 assert(!infeasible);
6861 assert(tightened);
6862 (*nfixedvars)++;
6863 }
6864
6865 SCIP_CALL( SCIPdelCons(scip, cons) );
6866 (*ndelconss)++;
6867 (*deleted) = TRUE;
6868 }
6869 }
6870
6871 SCIPfreeBufferArray(scip, &nonsolitems);
6872 SCIPfreeBufferArray(scip, &solitems);
6873 SCIPfreeBufferArray(scip, &items);
6874 SCIPfreeBufferArray(scip, &profits);
6875
6876 return SCIP_OKAY;
6877}
6878
6879/** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6880 * constraint enters the LP by setting the initial and separated flag to FALSE
6881 */
6882static
6884 SCIP* scip, /**< SCIP data structure */
6885 SCIP_CONS* cons, /**< knapsack constraint */
6886 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6887 )
6888{
6889 SCIP_CONSDATA* consdata;
6890 SCIP_VAR** vars;
6891 SCIP_VAR* var;
6892 SCIP_Real offset;
6893 SCIP_Real scale;
6895 SCIP_Bool applicable;
6896 SCIP_Bool negated;
6897 int nobjvars;
6898 int nvars;
6899 int v;
6900
6901 assert(scip != NULL);
6902 assert(cons != NULL);
6903 assert(conshdlrdata != NULL);
6904
6905 consdata = SCIPconsGetData(cons);
6906 assert(consdata != NULL);
6907
6908 nvars = consdata->nvars;
6909 nobjvars = SCIPgetNObjVars(scip);
6910
6911 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6912 * and/or separated flag is set to FALSE
6913 */
6914 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6915 return SCIP_OKAY;
6916
6917 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6918 * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6919 */
6920 if( nobjvars == 0 )
6921 return SCIP_OKAY;
6922
6923 vars = consdata->vars;
6924 assert(vars != NULL);
6925
6926 applicable = TRUE;
6927 offset = 0.0;
6928 scale = 1.0;
6929
6930 for( v = 0; v < nvars && applicable; ++v )
6931 {
6932 negated = FALSE;
6933 var = vars[v];
6934 assert(var != NULL);
6935
6936 if( SCIPvarIsNegated(var) )
6937 {
6938 negated = TRUE;
6940 assert(var != NULL);
6941 }
6942
6944
6945 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6946 if( SCIPisZero(scip, objval) )
6947 applicable = FALSE;
6948 else
6949 {
6950 SCIP_Real weight;
6951
6952 weight = (SCIP_Real)consdata->weights[v];
6953
6954 if( negated )
6955 {
6956 if( v == 0 )
6957 {
6958 /* the first variable defines the scale */
6959 scale = weight / -objval;
6960
6961 offset += weight;
6962 }
6963 else if( SCIPisEQ(scip, -objval * scale, weight) )
6964 offset += weight;
6965 else
6966 applicable = FALSE;
6967 }
6968 else if( v == 0 )
6969 {
6970 /* the first variable define the scale */
6971 scale = weight / objval;
6972 }
6973 else if( !SCIPisEQ(scip, objval * scale, weight) )
6974 applicable = FALSE;
6975 }
6976 }
6977
6978 if( applicable )
6979 {
6980 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6981 {
6982 SCIP_Real cutoffbound;
6983
6984 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6987
6988 cutoffbound = (consdata->capacity - offset) / scale;
6989
6990 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6991 SCIPconsGetName(cons), cutoffbound);
6992
6993 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6994 * still excepted
6995 */
6996 cutoffbound += SCIPcutoffbounddelta(scip);
6997
6998 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6999 SCIPconsGetName(cons), cutoffbound);
7000
7001 if( cutoffbound < SCIPgetCutoffbound(scip) )
7002 {
7003 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7004
7005 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7006 }
7007 else
7008 {
7009 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7010 * propagation
7011 */
7014 }
7015 }
7016 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7017 {
7018 SCIP_Real lowerbound;
7019
7020 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7023
7024 lowerbound = (consdata->capacity - offset) / scale;
7025
7026 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7027 SCIPconsGetName(cons), lowerbound);
7028
7030 }
7031 }
7032
7033 return SCIP_OKAY;
7034}
7035
7036/** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7037 * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7038static
7040 SCIP* scip, /**< SCIP data structure */
7041 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7042 SCIP_VAR** vars, /**< array for sorted variables */
7043 SCIP_Longint* weights, /**< array for sorted weights */
7044 int* cliquestartposs, /**< starting position array for each clique */
7045 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7046 )
7047{
7048 SCIP_VAR** origvars;
7049 int norigvars;
7050 SCIP_Longint* origweights;
7051 int* cliquepartition;
7052 int ncliques;
7053
7054 SCIP_VAR*** varpointers;
7055 SCIP_Longint** weightpointers;
7056 int* cliquecount;
7057
7058 int nextpos;
7059 int c;
7060 int v;
7061
7062 assert(scip != NULL);
7063 assert(consdata != NULL);
7064 assert(vars != NULL);
7065 assert(weights != NULL);
7066 assert(cliquestartposs != NULL);
7067
7068 origweights = consdata->weights;
7069 origvars = consdata->vars;
7070 norigvars = consdata->nvars;
7071
7072 assert(origvars != NULL || norigvars == 0);
7073 assert(origweights != NULL || norigvars == 0);
7074
7075 if( norigvars == 0 )
7076 return SCIP_OKAY;
7077
7078 if( usenegatedclique )
7079 {
7080 assert(consdata->negcliquepartitioned);
7081
7082 cliquepartition = consdata->negcliquepartition;
7083 ncliques = consdata->nnegcliques;
7084 }
7085 else
7086 {
7087 assert(consdata->cliquepartitioned);
7088
7089 cliquepartition = consdata->cliquepartition;
7090 ncliques = consdata->ncliques;
7091 }
7092
7093 assert(cliquepartition != NULL);
7094 assert(ncliques > 0);
7095
7096 /* we first count all clique items and alloc temporary memory for a bucket sort */
7097 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7098 BMSclearMemoryArray(cliquecount, ncliques);
7099
7100 /* first we count for each clique the number of elements */
7101 for( v = norigvars - 1; v >= 0; --v )
7102 {
7103 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7104 ++(cliquecount[cliquepartition[v]]);
7105 }
7106
7107 /*@todo: maybe it is better to put largest cliques up front */
7108
7109#ifndef NDEBUG
7110 BMSclearMemoryArray(vars, norigvars);
7111 BMSclearMemoryArray(weights, norigvars);
7112#endif
7113 SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7114 SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7115
7116 nextpos = 0;
7117 /* now we initialize all start pointers for each clique, so they will be ordered */
7118 for( c = 0; c < ncliques; ++c )
7119 {
7120 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7121 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7122 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7123 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7124 * vars[7]
7125 *
7126 */
7127 varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7128 cliquestartposs[c] = nextpos;
7129 weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7130 assert(cliquecount[c] > 0);
7131 nextpos += cliquecount[c];
7132 assert(nextpos > 0);
7133 }
7134 assert(nextpos == norigvars);
7135 cliquestartposs[c] = nextpos;
7136
7137 /* now we copy all variable and weights to the right order */
7138 for( v = 0; v < norigvars; ++v )
7139 {
7140 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7141 ++(varpointers[cliquepartition[v]]);
7142 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7143 ++(weightpointers[cliquepartition[v]]);
7144 }
7145#ifndef NDEBUG
7146 for( v = 0; v < norigvars; ++v )
7147 {
7148 assert(vars[v] != NULL);
7149 assert(weights[v] > 0);
7150 }
7151#endif
7152
7153 /* free temporary memory */
7154 SCIPfreeBufferArray(scip, &weightpointers);
7155 SCIPfreeBufferArray(scip, &varpointers);
7156 SCIPfreeBufferArray(scip, &cliquecount);
7157
7158 return SCIP_OKAY;
7159}
7160
7161/** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7162static
7164 SCIP* scip, /**< SCIP data structure */
7165 SCIP_CONS* cons, /**< knapsack constraint */
7166 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7167 * information is not needed; in this case, we apply all fixings
7168 * instead of stopping after the first infeasible one */
7169 )
7170{
7171 SCIP_CONSDATA* consdata;
7172 int v;
7173
7174 assert(scip != NULL);
7175 assert(cons != NULL);
7176
7177 consdata = SCIPconsGetData(cons);
7178 assert(consdata != NULL);
7179 assert(consdata->nvars == 0 || consdata->vars != NULL);
7180
7181 if( cutoff != NULL )
7182 *cutoff = FALSE;
7183
7184 SCIPdebugMsg(scip, "apply fixings:\n");
7186
7187 /* check infeasibility */
7188 if ( consdata->onesweightsum > consdata->capacity )
7189 {
7190 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7191
7192 if( cutoff != NULL )
7193 *cutoff = TRUE;
7194
7195 return SCIP_OKAY;
7196 }
7197
7198 /* all multi-aggregations should be resolved */
7199 consdata->existmultaggr = FALSE;
7200
7201 v = 0;
7202 while( v < consdata->nvars )
7203 {
7204 SCIP_VAR* var;
7205
7206 var = consdata->vars[v];
7208
7209 if( SCIPvarGetLbGlobal(var) > 0.5 )
7210 {
7212 consdata->capacity -= consdata->weights[v];
7213 SCIP_CALL( delCoefPos(scip, cons, v) );
7214 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7215 }
7216 else if( SCIPvarGetUbGlobal(var) < 0.5 )
7217 {
7219 SCIP_CALL( delCoefPos(scip, cons, v) );
7220 }
7221 else
7222 {
7223 SCIP_VAR* repvar;
7224 SCIP_VAR* negvar;
7225 SCIP_VAR* workvar;
7226 SCIP_Longint weight;
7227 SCIP_Bool negated;
7228
7229 weight = consdata->weights[v];
7230
7231 /* get binary representative of variable */
7232 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7233 assert(repvar != NULL);
7234
7235 /* check for multi-aggregation */
7236 if( SCIPvarIsNegated(repvar) )
7237 {
7238 workvar = SCIPvarGetNegatedVar(repvar);
7239 assert(workvar != NULL);
7240 negated = TRUE;
7241 }
7242 else
7243 {
7244 workvar = repvar;
7245 negated = FALSE;
7246 }
7247
7248 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7249 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7250 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7251 *
7252 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7253 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7254 *
7255 * The explanation for the following block:
7256 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7257 * weight * (a_1*y_1 + ... + a_n*y_n + c).
7258 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7259 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7260 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7261 * 2) For all replacement variable we check:
7262 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7263 * capacity -= weight * a_i caused by the negation of y_i.
7264 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7265 * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7266 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7267 * weight in this case.
7268 */
7270 {
7271 SCIP_VAR** aggrvars;
7272 SCIP_Real* aggrscalars;
7273 SCIP_Real aggrconst;
7274 int naggrvars;
7275 int i;
7276
7278 naggrvars = SCIPvarGetMultaggrNVars(workvar);
7279 aggrvars = SCIPvarGetMultaggrVars(workvar);
7280 aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7281 aggrconst = SCIPvarGetMultaggrConstant(workvar);
7282 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7283
7284 if( !SCIPisIntegral(scip, weight * aggrconst) )
7285 {
7286 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7287 return SCIP_ERROR;
7288 }
7289
7290 /* if workvar was negated, we have to flip the weight */
7291 if( negated )
7292 weight *= -1;
7293
7294 for( i = naggrvars - 1; i >= 0; --i )
7295 {
7296 assert(aggrvars != NULL);
7297 assert(aggrscalars != NULL);
7298
7299 if( !SCIPvarIsBinary(aggrvars[i]) )
7300 {
7301 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7302 SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7303 return SCIP_ERROR;
7304 }
7305 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7306 {
7307 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7308 return SCIP_ERROR;
7309 }
7310 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7311 if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7312 {
7313 SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar) );
7314 assert(negvar != NULL);
7315 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7316 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7317 }
7318 else
7319 {
7320 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7321 }
7322 }
7323 /* delete old coefficient */
7324 SCIP_CALL( delCoefPos(scip, cons, v) );
7325
7326 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7327 if( negated )
7328 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7329 else
7330 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7331
7332 if( consdata->capacity < 0 )
7333 {
7334 if( cutoff != NULL )
7335 {
7336 *cutoff = TRUE;
7337 break;
7338 }
7339 }
7340 }
7341 /* check, if the variable should be replaced with the representative */
7342 else if( repvar != var )
7343 {
7344 /* delete old (aggregated) variable */
7345 SCIP_CALL( delCoefPos(scip, cons, v) );
7346
7347 /* add representative instead */
7348 SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7349 }
7350 else
7351 ++v;
7352 }
7353 }
7354 assert(consdata->onesweightsum == 0);
7355
7356 SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7358
7359 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7360 * clean up the constraint
7361 */
7362 if( cutoff != NULL && !(*cutoff) )
7363 {
7365 SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7367 }
7368
7369 return SCIP_OKAY;
7370}
7371
7372
7373/** propagation method for knapsack constraints */
7374static
7376 SCIP* scip, /**< SCIP data structure */
7377 SCIP_CONS* cons, /**< knapsack constraint */
7378 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7379 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7380 int* nfixedvars, /**< pointer to count number of fixings */
7381 SCIP_Bool usenegatedclique /**< should negated clique information be used */
7382 )
7383{
7384 SCIP_CONSDATA* consdata;
7385 SCIP_Bool infeasible;
7386 SCIP_Bool tightened;
7387 SCIP_Longint* secondmaxweights;
7388 SCIP_Longint minweightsum;
7389 SCIP_Longint residualcapacity;
7390
7391 int nvars;
7392 int i;
7393 int nnegcliques;
7394
7395 SCIP_VAR** myvars;
7396 SCIP_Longint* myweights;
7397 int* cliquestartposs;
7398 int* cliqueendposs;
7399 SCIP_Longint localminweightsum;
7400 SCIP_Bool foundmax;
7401 int c;
7402
7403 assert(scip != NULL);
7404 assert(cons != NULL);
7405 assert(cutoff != NULL);
7406 assert(redundant != NULL);
7407 assert(nfixedvars != NULL);
7408
7409 consdata = SCIPconsGetData(cons);
7410 assert(consdata != NULL);
7411
7412 *cutoff = FALSE;
7413 *redundant = FALSE;
7414
7415 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7416
7417 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7419 {
7420 SCIP_CALL( SCIPincConsAge(scip, cons) );
7421 }
7422
7423#ifndef NDEBUG
7424 /* assert that only active or negated variables are present */
7425 for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7426 {
7427 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7428 }
7429#endif
7430
7431 usenegatedclique = usenegatedclique && consdata->merged;
7432
7433 /* init for debugging */
7434 myvars = NULL;
7435 myweights = NULL;
7436 cliquestartposs = NULL;
7437 secondmaxweights = NULL;
7438 minweightsum = 0;
7439 nvars = consdata->nvars;
7440 /* make sure, the items are sorted by non-increasing weight */
7441 sortItems(consdata);
7442
7443 do
7444 {
7445 localminweightsum = 0;
7446
7447 /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7448 * a negated clique means, that at most one of the clique variables can be zero
7449 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7450 *
7451 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7452 * since replacing i with the element of maximal weight leads to infeasibility
7453 */
7454 if( usenegatedclique && nvars > 0 )
7455 {
7456 SCIP_CONSHDLRDATA* conshdlrdata;
7457 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7458 assert(conshdlrdata != NULL);
7459
7460 /* compute clique partitions */
7461 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7462 nnegcliques = consdata->nnegcliques;
7463
7464 /* if we have no real negated cliques we can stop here */
7465 if( nnegcliques == nvars )
7466 {
7467 /* run the standard algorithm that does not involve cliques */
7468 usenegatedclique = FALSE;
7469 break;
7470 }
7471
7472 /* allocate temporary memory and initialize it */
7473 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7474 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7475 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7476 SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7477 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7478 BMSclearMemoryArray(secondmaxweights, nnegcliques);
7479
7480 /* resort variables to avoid quadratic algorithm later on */
7481 SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7482
7483 /* save the end positions of the cliques because start positions are moved in the following loop */
7484 for( c = 0; c < nnegcliques; ++c )
7485 {
7486 cliqueendposs[c] = cliquestartposs[c+1] - 1;
7487 assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7488 }
7489
7490 c = 0;
7491 foundmax = FALSE;
7492 i = 0;
7493
7494 while( i < nvars )
7495 {
7496 /* ignore variables of the negated clique which are fixed to one since these are counted in
7497 * consdata->onesweightsum
7498 */
7499
7500 /* if there are only one variable negated cliques left we can stop */
7501 if( nnegcliques - c == nvars - i )
7502 {
7503 minweightsum += localminweightsum;
7504 localminweightsum = 0;
7505 break;
7506 }
7507
7508 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7509 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7510 * other clique variables to one
7511 */
7512 if( cliquestartposs[c] == i )
7513 {
7514 assert(myweights[i] > 0);
7515 ++c;
7516 minweightsum += localminweightsum;
7517 localminweightsum = 0;
7518 foundmax = TRUE;
7519
7520 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7521 foundmax = FALSE;
7522
7523 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7524 {
7525 ++i;
7526 continue;
7527 }
7528 }
7529
7530 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7531 {
7532 assert(myweights[i] > 0);
7533
7534 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7535 {
7536 assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7537
7538 if( !foundmax )
7539 {
7540 foundmax = TRUE;
7541
7542 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7543 cliquestartposs[c - 1] = i;
7544 ++i;
7545
7546 continue;
7547 }
7548 /* memorize second max weight for each clique */
7549 if( secondmaxweights[c - 1] == 0 )
7550 secondmaxweights[c - 1] = myweights[i];
7551
7552 localminweightsum += myweights[i];
7553 }
7554 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7555 else
7556 {
7557 int v;
7558 /* fix all other variables of the negated clique to 1 */
7559 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7560 {
7561 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7562 {
7563 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7564 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7565
7566 if( infeasible )
7567 {
7568 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7569
7570 /* analyze the infeasibility if conflict analysis is applicable */
7572 {
7573 /* conflict analysis can only be applied in solving stage */
7575
7576 /* initialize the conflict analysis */
7578
7579 /* add the two variables which are fixed to zero within a negated clique */
7581 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7582
7583 /* start the conflict analysis */
7585 }
7586 *cutoff = TRUE;
7587 break;
7588 }
7589 assert(tightened);
7590 ++(*nfixedvars);
7592 }
7593 }
7594
7595 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7596 localminweightsum = 0;
7597 /* we can jump to the end of this clique */
7598 i = cliqueendposs[c - 1];
7599
7600 if( *cutoff )
7601 break;
7602 }
7603 }
7604 ++i;
7605 }
7606 /* add last clique minweightsum */
7607 minweightsum += localminweightsum;
7608
7609 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7610 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7611
7612 /* check, if weights of fixed variables don't exceeds knapsack capacity */
7613 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7614 {
7615 SCIP_Longint maxcliqueweight = -1LL;
7616
7617 /* loop over cliques */
7618 for( c = 0; c < nnegcliques; ++c )
7619 {
7620 SCIP_VAR* maxvar;
7621 SCIP_Bool maxvarfixed;
7622 int endvarposclique;
7623 int startvarposclique;
7624
7625 assert(myvars != NULL);
7626 assert(nnegcliques == consdata->nnegcliques);
7627 assert(myweights != NULL);
7628 assert(secondmaxweights != NULL);
7629 assert(cliquestartposs != NULL);
7630
7631 endvarposclique = cliqueendposs[c];
7632 startvarposclique = cliquestartposs[c];
7633
7634 maxvar = myvars[startvarposclique];
7635
7636 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7637 if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7638 continue;
7639
7640 maxcliqueweight = myweights[startvarposclique];
7641 maxvarfixed = FALSE;
7642 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7643 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7644 * exceeds the capacity the maximum weight variable can be fixed to zero.
7645 */
7646 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7647 {
7648#ifndef NDEBUG
7649 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7650#endif
7651 assert(maxcliqueweight >= secondmaxweights[c]);
7652 assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7653
7654 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7656 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7657 assert(consdata->onesweightsum == oldonesweightsum);
7658 assert(!infeasible);
7659 assert(tightened);
7660 (*nfixedvars)++;
7661 maxvarfixed = TRUE;
7662 }
7663 /* the remaining cliques are singletons such that all subsequent variables have a weight that
7664 * fits into the knapsack
7665 */
7666 else if( nnegcliques - c == nvars - startvarposclique )
7667 break;
7668 /* early termination of the remaining loop because no further variable fixings are possible:
7669 *
7670 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7671 * largest was set to 0) does not suffice to infer additional variable fixings because
7672 *
7673 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7674 * - their second largest elements are at least as large as the smallest weight of the knapsack
7675 */
7676 else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7677 break;
7678
7679 /* loop over items with non-maximal weight (omitting the first position) */
7680 for( i = endvarposclique; i > startvarposclique; --i )
7681 {
7682 /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7683 * messed up the clique preprocessing in the previous loop to filter those variables out */
7684 assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7685
7686 /* only check variables of negated cliques for which no variable is locally fixed */
7687 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7688 {
7689 assert(maxcliqueweight >= myweights[i]);
7690 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7691
7692 /* we fix the members of this clique with non-maximal weight in two cases to 1:
7693 *
7694 * the maxvar was already fixed to 0 because it has a huge gain.
7695 *
7696 * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7697 * since replacing i with the element of maximal weight leads to infeasibility */
7698 if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7699 {
7700#ifndef NDEBUG
7701 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7702#endif
7703 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7704 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7705 assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7706 assert(!infeasible);
7707 assert(tightened);
7708 ++(*nfixedvars);
7710
7711 /* update minweightsum because now the variable is fixed to one and its weight is counted by
7712 * consdata->onesweightsum
7713 */
7714 minweightsum -= myweights[i];
7715 assert(minweightsum >= 0);
7716 }
7717 else
7718 break;
7719 }
7720 }
7721#ifndef NDEBUG
7722 /* in debug mode, we assert that we did not miss possible fixings by the break above */
7723 for( ; i > startvarposclique; --i )
7724 {
7725 SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7726 SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7727
7728 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7729 assert(varisfixed || !exceedscapacity);
7730 }
7731#endif
7732 }
7733 }
7734 SCIPfreeBufferArray(scip, &secondmaxweights);
7735 SCIPfreeBufferArray(scip, &cliqueendposs);
7736 SCIPfreeBufferArray(scip, &cliquestartposs);
7737 SCIPfreeBufferArray(scip, &myweights);
7738 SCIPfreeBufferArray(scip, &myvars);
7739 }
7740
7741 assert(consdata->negcliquepartitioned || minweightsum == 0);
7742 }
7743 while( FALSE );
7744
7745 assert(usenegatedclique || minweightsum == 0);
7746 /* check, if weights of fixed variables already exceed knapsack capacity */
7747 if( consdata->capacity < minweightsum + consdata->onesweightsum )
7748 {
7749 SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7750 consdata->onesweightsum, consdata->capacity);
7751
7753 *cutoff = TRUE;
7754
7755 /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7757 {
7758 /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7759 SCIP_Longint weight;
7760
7761 weight = 0;
7762
7764
7765 for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7766 {
7767 if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7768 {
7769 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7770 weight += consdata->weights[i];
7771 }
7772 }
7773
7775 }
7776
7777 return SCIP_OKAY;
7778 }
7779
7780 /* the algorithm below is a special case of propagation involving negated cliques */
7781 if( !usenegatedclique )
7782 {
7783 assert(consdata->sorted);
7784 residualcapacity = consdata->capacity - consdata->onesweightsum;
7785
7786 /* fix all variables to zero, that don't fit into the knapsack anymore */
7787 for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7788 {
7789 /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7790 * to zero
7791 */
7792 if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7793 {
7794 if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7795 {
7796 assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7797 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7799 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7800 assert(!infeasible);
7801 assert(tightened);
7802 (*nfixedvars)++;
7803 }
7804 }
7805 }
7806 }
7807
7808 /* check if the knapsack is now redundant */
7809 if( !SCIPconsIsModifiable(cons) )
7810 {
7811 SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7812
7813 /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7814 for( i = 0; i < nvars; ++i )
7815 {
7816 if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7817 {
7818 unfixedweightsum += consdata->weights[i];
7819
7820 /* the weight sum is larger than the capacity, so the constraint is not redundant */
7821 if( unfixedweightsum > consdata->capacity )
7822 return SCIP_OKAY;
7823 }
7824 }
7825 /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7826 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7827 SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7829 *redundant = TRUE;
7830 }
7831
7832 return SCIP_OKAY;
7833}
7834
7835/** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7836 * containing all negated variables of this knapsack constraint
7837 */
7838static
7840 SCIP* scip, /**< SCIP data structure */
7841 SCIP_CONS* cons, /**< knapsack constraint */
7842 int* ndelconss, /**< pointer to store the amount of deleted constraints */
7843 int* naddconss /**< pointer to count number of added constraints */
7844 )
7845{
7846 SCIP_CONS* newcons;
7847 SCIP_CONSDATA* consdata;
7848
7849 assert(scip != NULL);
7850 assert(cons != NULL);
7851 assert(ndelconss != NULL);
7852 assert(naddconss != NULL);
7853
7854 consdata = SCIPconsGetData(cons);
7855 assert(consdata != NULL);
7856 assert(consdata->nvars > 1);
7857
7858 /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7859 if( consdata->nvars == 2 )
7860 {
7861 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7862
7863 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7867 SCIPconsIsStickingAtNode(cons)) );
7868 }
7869 /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7870 * containing all negated variables of the knapsack
7871 */
7872 else
7873 {
7874 SCIP_VAR** consvars;
7875
7876 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7877
7878 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7879 SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7880
7881 SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7885 SCIPconsIsStickingAtNode(cons)) );
7886
7887 SCIPfreeBufferArray(scip, &consvars);
7888 }
7889
7890 /* add the upgraded constraint to the problem */
7891 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
7892 ++(*naddconss);
7893
7894 /* remove the underlying constraint from the problem */
7895 SCIP_CALL( SCIPdelCons(scip, cons) );
7896 ++(*ndelconss);
7897
7898 return SCIP_OKAY;
7899}
7900
7901/** delete redundant variables
7902 *
7903 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7904 *
7905 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7906 * => x4, x5 always fits into the knapsack, so we can delete them
7907 *
7908 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7909 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7910 */
7911static
7913 SCIP* scip, /**< SCIP data structure */
7914 SCIP_CONS* cons, /**< knapsack constraint */
7915 SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7916 int splitpos, /**< split position till when all front items are fitting, splitpos is the
7917 * first which did not fit */
7918 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7919 int* nchgsides, /**< pointer to store the amount of changed sides */
7920 int* naddconss /**< pointer to count number of added constraints */
7921 )
7922{
7923 SCIP_CONSHDLRDATA* conshdlrdata;
7924 SCIP_CONSDATA* consdata;
7925 SCIP_VAR** vars;
7926 SCIP_Longint* weights;
7927 SCIP_Longint capacity;
7928 SCIP_Longint gcd;
7929 int nvars;
7930 int w;
7931
7932 assert(scip != NULL);
7933 assert(cons != NULL);
7934 assert(nchgcoefs != NULL);
7935 assert(nchgsides != NULL);
7936 assert(naddconss != NULL);
7937
7938 consdata = SCIPconsGetData(cons);
7939 assert(consdata != NULL);
7940 assert(0 < frontsum && frontsum < consdata->weightsum);
7941 assert(0 < splitpos && splitpos < consdata->nvars);
7942
7943 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7944 assert(conshdlrdata != NULL);
7945
7946 vars = consdata->vars;
7947 weights = consdata->weights;
7948 nvars = consdata->nvars;
7949 capacity = consdata->capacity;
7950
7951 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7952 * weight must not be sorted by their index
7953 */
7954#ifndef NDEBUG
7955 for( w = nvars - 1; w > 0; --w )
7956 assert(weights[w] <= weights[w-1]);
7957#endif
7958
7959 /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7960 if( consdata->nvars - 1 == splitpos )
7961 return SCIP_OKAY;
7962
7963 assert(frontsum + weights[splitpos] > capacity);
7964
7965 /* detect redundant variables */
7966 if( consdata->weightsum - weights[splitpos] <= capacity )
7967 {
7968 /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7969 * fit
7970 */
7971 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7972
7973 /* delete items and update capacity */
7974 for( w = nvars - 1; w > splitpos; --w )
7975 {
7976 consdata->capacity -= weights[w];
7977 SCIP_CALL( delCoefPos(scip, cons, w) );
7978 }
7979 assert(w == splitpos);
7980
7981 ++(*nchgsides);
7982 *nchgcoefs += (nvars - splitpos);
7983
7984 /* division by greatest common divisor */
7985 gcd = weights[w];
7986 for( ; w >= 0 && gcd > 1; --w )
7987 {
7988 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7989 }
7990
7991 /* normalize if possible */
7992 if( gcd > 1 )
7993 {
7994 for( w = splitpos; w >= 0; --w )
7995 {
7996 consdataChgWeight(consdata, w, weights[w]/gcd);
7997 }
7998 (*nchgcoefs) += nvars;
7999
8000 consdata->capacity /= gcd;
8001 ++(*nchgsides);
8002 }
8003
8004 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8005 * weight must not be sorted by their index
8006 */
8007#ifndef NDEBUG
8008 for( w = consdata->nvars - 1; w > 0; --w )
8009 assert(weights[w] <= weights[w - 1]);
8010#endif
8011 }
8012 /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8013 * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8014 * splitpos and needs to fit into the knapsack
8015 */
8016 else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8017 {
8018 int* clqpart;
8019 int nclq;
8020 int len;
8021
8022 len = nvars - (splitpos + 1);
8023 /* allocate temporary memory */
8024 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8025
8026 /* calculate clique partition */
8027 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
8028
8029 /* check if we found at least one clique */
8030 if( nclq < len )
8031 {
8032 SCIP_Longint maxactduetoclq;
8033 int cliquenum;
8034
8035 maxactduetoclq = 0;
8036 cliquenum = 0;
8037
8038 /* calculate maximum activity due to cliques */
8039 for( w = 0; w < len; ++w )
8040 {
8041 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8042 if( clqpart[w] == cliquenum )
8043 {
8044 maxactduetoclq += weights[w + splitpos + 1];
8045 ++cliquenum;
8046 }
8047 }
8048
8049 /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8050 * so delete them and create for all clique the corresponding clique constraints and update the capacity
8051 */
8052 if( frontsum + maxactduetoclq <= capacity )
8053 {
8054 SCIP_VAR** clqvars;
8055 int nclqvars;
8056 int c;
8057
8058 assert(maxactduetoclq < weights[splitpos]);
8059
8060 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8061
8062 /* allocate temporary memory */
8063 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8064
8065 for( c = 0; c < nclq; ++c )
8066 {
8067 nclqvars = 0;
8068 for( w = 0; w < len; ++w )
8069 {
8070 if( clqpart[w] == c )
8071 {
8072 clqvars[nclqvars] = vars[w + splitpos + 1];
8073 ++nclqvars;
8074 }
8075 }
8076
8077 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8078 if( nclqvars > 1 )
8079 {
8080 SCIP_CONS* cliquecons;
8081 char name[SCIP_MAXSTRLEN];
8082
8083 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8084 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8088 SCIPconsIsStickingAtNode(cons)) );
8089
8090 /* add the special constraint to the problem */
8091 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8092 SCIPdebugPrintCons(scip, cliquecons, NULL);
8093 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8094 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8095 ++(*naddconss);
8096 }
8097 }
8098
8099 /* delete items and update capacity */
8100 for( w = nvars - 1; w > splitpos; --w )
8101 {
8102 SCIP_CALL( delCoefPos(scip, cons, w) );
8103 ++(*nchgcoefs);
8104 }
8105 consdata->capacity -= maxactduetoclq;
8106 assert(frontsum <= consdata->capacity);
8107 ++(*nchgsides);
8108
8109 assert(w == splitpos);
8110
8111 /* renew weights pointer */
8112 weights = consdata->weights;
8113
8114 /* division by greatest common divisor */
8115 gcd = weights[w];
8116 for( ; w >= 0 && gcd > 1; --w )
8117 {
8118 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8119 }
8120
8121 /* normalize if possible */
8122 if( gcd > 1 )
8123 {
8124 for( w = splitpos; w >= 0; --w )
8125 {
8126 consdataChgWeight(consdata, w, weights[w]/gcd);
8127 }
8128 (*nchgcoefs) += nvars;
8129
8130 consdata->capacity /= gcd;
8131 ++(*nchgsides);
8132 }
8133
8134 /* free temporary memory */
8135 SCIPfreeBufferArray(scip, &clqvars);
8136
8137 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8138 * weight must not be sorted by their index
8139 */
8140#ifndef NDEBUG
8141 for( w = consdata->nvars - 1; w > 0; --w )
8142 assert(weights[w] <= weights[w - 1]);
8143#endif
8144 }
8145 }
8146
8147 /* free temporary memory */
8148 SCIPfreeBufferArray(scip, &clqpart);
8149 }
8150
8151 return SCIP_OKAY;
8152}
8153
8154/* detect redundant variables which always fits into the knapsack
8155 *
8156 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8157 *
8158 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8159 * => x4, x5 always fits into the knapsack, so we can delete them
8160 *
8161 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8162 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8163 */
8164static
8166 SCIP* scip, /**< SCIP data structure */
8167 SCIP_CONS* cons, /**< knapsack constraint */
8168 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8169 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8170 int* nchgsides, /**< pointer to store the amount of changed sides */
8171 int* naddconss /**< pointer to count number of added constraints */
8172 )
8173{
8174 SCIP_CONSHDLRDATA* conshdlrdata;
8175 SCIP_CONSDATA* consdata;
8176 SCIP_VAR** vars;
8177 SCIP_Longint* weights;
8178 SCIP_Longint capacity;
8179 SCIP_Longint sum;
8180 int nvars;
8181 int v;
8182 int w;
8183
8184 assert(scip != NULL);
8185 assert(cons != NULL);
8186 assert(ndelconss != NULL);
8187 assert(nchgcoefs != NULL);
8188 assert(nchgsides != NULL);
8189 assert(naddconss != NULL);
8190
8191 consdata = SCIPconsGetData(cons);
8192 assert(consdata != NULL);
8193 assert(consdata->nvars >= 2);
8194 assert(consdata->weightsum > consdata->capacity);
8195
8196 vars = consdata->vars;
8197 weights = consdata->weights;
8198 nvars = consdata->nvars;
8199 capacity = consdata->capacity;
8200 sum = 0;
8201
8202 /* search for maximal fitting items */
8203 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8204 sum += weights[v];
8205
8206 assert(v < nvars);
8207
8208 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8209 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == nvars - 1 )
8210 {
8211 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8213
8214 return SCIP_OKAY;
8215 }
8216
8217 if( v < nvars - 1 )
8218 {
8219 /* try to delete variables */
8220 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8221 assert(consdata->nvars > 1);
8222
8223 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8224 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == consdata->nvars - 1 )
8225 {
8226 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8228 }
8229
8230 return SCIP_OKAY;
8231 }
8232
8233 assert(vars == consdata->vars);
8234 assert(weights == consdata->weights);
8235 assert(nvars == consdata->nvars);
8236 assert(capacity == consdata->capacity);
8237
8238 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8239 assert(conshdlrdata != NULL);
8240 /* calculate clique partition */
8241 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8242
8243 /* check for real existing cliques */
8244 if( consdata->cliquepartition[v] < v )
8245 {
8246 SCIP_Longint sumfront;
8247 SCIP_Longint maxactduetoclqfront;
8248 int* clqpart;
8249 int cliquenum;
8250
8251 sumfront = 0;
8252 maxactduetoclqfront = 0;
8253
8254 clqpart = consdata->cliquepartition;
8255 cliquenum = 0;
8256
8257 /* calculate maximal activity due to cliques */
8258 for( w = 0; w < nvars; ++w )
8259 {
8260 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8261 if( clqpart[w] == cliquenum )
8262 {
8263 if( maxactduetoclqfront + weights[w] <= capacity )
8264 {
8265 maxactduetoclqfront += weights[w];
8266 ++cliquenum;
8267 }
8268 else
8269 break;
8270 }
8271 sumfront += weights[w];
8272 }
8273 assert(w >= v);
8274
8275 /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8276 * information
8277 */
8278 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0 && w == nvars )
8279 {
8280 SCIP_VAR** clqvars;
8281 int nclqvars;
8282 int c;
8283 int ncliques;
8284
8285 assert(maxactduetoclqfront <= capacity);
8286
8287 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8288
8289 ncliques = consdata->ncliques;
8290
8291 /* allocate temporary memory */
8292 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8293
8294 for( c = 0; c < ncliques; ++c )
8295 {
8296 nclqvars = 0;
8297 for( w = 0; w < nvars; ++w )
8298 {
8299 if( clqpart[w] == c )
8300 {
8301 clqvars[nclqvars] = vars[w];
8302 ++nclqvars;
8303 }
8304 }
8305
8306 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8307 if( nclqvars > 1 )
8308 {
8309 SCIP_CONS* cliquecons;
8310 char name[SCIP_MAXSTRLEN];
8311
8312 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8313 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8317 SCIPconsIsStickingAtNode(cons)) );
8318
8319 /* add the special constraint to the problem */
8320 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8321 SCIPdebugPrintCons(scip, cliquecons, NULL);
8322 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8323 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8324 ++(*naddconss);
8325 }
8326 }
8327
8328 /* delete old constraint */
8329 SCIP_CALL( SCIPdelCons(scip, cons) );
8330 ++(*ndelconss);
8331
8332 SCIPfreeBufferArray(scip, &clqvars);
8333
8334 return SCIP_OKAY;
8335 }
8336
8337 if( w > v && w < nvars - 1 )
8338 {
8339 /* try to delete variables */
8340 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8341 }
8342 }
8343
8344 return SCIP_OKAY;
8345}
8346
8347/** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8348static
8350 SCIP_CONS* cons, /**< knapsack constraint */
8351 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8352 int* nchgsides /**< pointer to count number of side changes */
8353 )
8354{
8355 SCIP_CONSDATA* consdata;
8356 SCIP_Longint gcd;
8357 int i;
8358
8359 assert(nchgcoefs != NULL);
8360 assert(nchgsides != NULL);
8362
8363 consdata = SCIPconsGetData(cons);
8364 assert(consdata != NULL);
8365 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8366 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8367 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8368 assert(consdata->nvars >= 1);
8369
8370 /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8371 sortItems(consdata);
8372
8373 gcd = consdata->weights[consdata->nvars-1];
8374 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8375 {
8376 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8377 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8378
8379 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8380 }
8381
8382 if( gcd >= 2 )
8383 {
8384 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8385
8386 for( i = 0; i < consdata->nvars; ++i )
8387 {
8388 consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8389 }
8390 consdata->capacity /= gcd;
8391 (*nchgcoefs) += consdata->nvars;
8392 (*nchgsides)++;
8393
8394 /* weight should still be sorted, because the reduction preserves this */
8395#ifndef NDEBUG
8396 for( i = consdata->nvars - 1; i > 0; --i )
8397 assert(consdata->weights[i] <= consdata->weights[i - 1]);
8398#endif
8399 consdata->sorted = TRUE;
8400 }
8401}
8402
8403/** dual weights tightening for knapsack constraints
8404 *
8405 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8406 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8407 * constraint
8408 *
8409 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8410 * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8411 *
8412 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8413 *
8414 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8415 *
8416 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8417 *
8418 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8419 *
8420 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8421 */
8422static
8424 SCIP* scip, /**< SCIP data structure */
8425 SCIP_CONS* cons, /**< knapsack constraint */
8426 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8427 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8428 int* nchgsides, /**< pointer to store the amount of changed sides */
8429 int* naddconss /**< pointer to count number of added constraints */
8430 )
8431{
8432 SCIP_CONSDATA* consdata;
8433 SCIP_Longint* weights;
8434 SCIP_Longint dualcapacity;
8435 SCIP_Longint reductionsum;
8436 SCIP_Longint capacity;
8437 SCIP_Longint exceedsum;
8438 int oldnchgcoefs;
8439 int nvars;
8440 int vbig;
8441 int v;
8442 int w;
8443#ifndef NDEBUG
8444 int oldnchgsides;
8445#endif
8446
8447 assert(scip != NULL);
8448 assert(cons != NULL);
8449 assert(ndelconss != NULL);
8450 assert(nchgcoefs != NULL);
8451 assert(nchgsides != NULL);
8452 assert(naddconss != NULL);
8453
8454 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
8455 return SCIP_OKAY;
8456
8457#ifndef NDEBUG
8458 oldnchgsides = *nchgsides;
8459#endif
8460
8461 consdata = SCIPconsGetData(cons);
8462 assert(consdata != NULL);
8463 assert(consdata->weightsum > consdata->capacity);
8464 assert(consdata->nvars >= 2);
8465 assert(consdata->sorted);
8466
8467 /* constraint should be merged */
8468 assert(consdata->merged);
8469
8470 nvars = consdata->nvars;
8471 weights = consdata->weights;
8472 capacity = consdata->capacity;
8473
8474 oldnchgcoefs = *nchgcoefs;
8475
8476 /* case 1. */
8477 if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8478 {
8479 SCIP_CONS* newcons;
8480
8481 /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8482 *
8483 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8484 */
8485 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8486
8487 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8491 SCIPconsIsStickingAtNode(cons)) );
8492
8493 /* add the upgraded constraint to the problem */
8494 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
8495 ++(*naddconss);
8496
8497 /* remove the underlying constraint from the problem */
8498 SCIP_CALL( SCIPdelCons(scip, cons) );
8499 ++(*ndelconss);
8500
8501 return SCIP_OKAY;
8502 }
8503
8504 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8505 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8506 {
8507 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8509
8510 return SCIP_OKAY;
8511 }
8512
8513 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8514 /* @todo might be changed/removed when improving the coeffcients tightening */
8515 if( consdata->weightsum - capacity > weights[0] + weights[1] )
8516 return SCIP_OKAY;
8517
8518 /* case 2. */
8519
8520 v = 0;
8521
8522 /* @todo generalize the following algorithm for several parts of the knapsack
8523 *
8524 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8525 * variables each combination is a minimal cover, some examples
8526 *
8527 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8528 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8529 * <=> x1 + x2 + x3 + x4 + x5 <= 3
8530 *
8531 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8532 *
8533 */
8534
8535 /* determine big weights that fit only by itself */
8536 while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8537 ++v;
8538
8539 vbig = v;
8540 assert(vbig < nvars - 1);
8541 exceedsum = 0;
8542
8543 /* determine the amount needed to exceed the capacity */
8544 while( v < nvars && exceedsum <= capacity )
8545 {
8546 exceedsum += weights[v];
8547 ++v;
8548 }
8549
8550 /* if we exceeded the capacity we might reduce the weights */
8551 if( exceedsum > capacity )
8552 {
8553 assert(vbig > 0 || v < nvars);
8554
8555 /* all small weights were needed to exceed the capacity */
8556 if( v == nvars )
8557 {
8558 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8559 assert(newweight > 0);
8560
8561 /* reduce big weights */
8562 for( v = 0; v < vbig; ++v )
8563 {
8564 if( weights[v] > newweight )
8565 {
8566 consdataChgWeight(consdata, v, newweight);
8567 ++(*nchgcoefs);
8568 }
8569 }
8570
8571 /* reduce small weights */
8572 for( ; v < nvars; ++v )
8573 {
8574 if( weights[v] > 1 )
8575 {
8576 consdataChgWeight(consdata, v, 1LL);
8577 ++(*nchgcoefs);
8578 }
8579 }
8580
8581 consdata->capacity = newweight;
8582
8583 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8584 * weight must not be sorted by their index
8585 */
8586#ifndef NDEBUG
8587 for( v = nvars - 1; v > 0; --v )
8588 assert(weights[v] <= weights[v-1]);
8589#endif
8590
8591 return SCIP_OKAY;
8592 }
8593 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8594 * small weights
8595 */
8596 else
8597 {
8598 SCIP_Longint exceedsumback = 0;
8599 int nexceed = v - vbig;
8600
8601 assert(nexceed > 1);
8602
8603 /* determine weightsum of the same amount as before but of the smallest weight */
8604 for( w = nvars - 1; w >= nvars - nexceed; --w )
8605 exceedsumback += weights[w];
8606
8607 assert(w >= 0);
8608
8609 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8610 * combinations of all small weights
8611 */
8612 if( exceedsumback > capacity )
8613 {
8614 SCIP_Longint newweight = nexceed - 1;
8615
8616 /* taking out the smallest element needs to fit */
8617 assert(exceedsumback - weights[nvars - 1] <= capacity);
8618
8619 /* reduce big weights */
8620 for( v = 0; v < vbig; ++v )
8621 {
8622 if( weights[v] > newweight )
8623 {
8624 consdataChgWeight(consdata, v, newweight);
8625 ++(*nchgcoefs);
8626 }
8627 }
8628
8629 /* reduce small weights */
8630 for( ; v < nvars; ++v )
8631 {
8632 if( weights[v] > 1 )
8633 {
8634 consdataChgWeight(consdata, v, 1LL);
8635 ++(*nchgcoefs);
8636 }
8637 }
8638
8639 consdata->capacity = newweight;
8640
8641 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8642 * weight must not be sorted by their index
8643 */
8644#ifndef NDEBUG
8645 for( v = nvars - 1; v > 0; --v )
8646 assert(weights[v] <= weights[v-1]);
8647#endif
8648 return SCIP_OKAY;
8649 }
8650 }
8651 }
8652 else
8653 {
8654 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8655 * not happen here
8656 */
8657 assert(vbig > 0 && vbig < nvars);
8658
8659 /* either choose a big coefficients or all other variables
8660 *
8661 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8662 *
8663 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8664 * constraint to
8665 *
8666 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8667 */
8668
8669 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8670 {
8671 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8672#ifndef NDEBUG
8673 SCIP_Longint resweightsum = consdata->weightsum;
8674
8675 for( v = 0; v < vbig; ++v )
8676 resweightsum -= weights[v];
8677
8678 assert(exceedsum == resweightsum);
8679#endif
8680 assert(newweight > 0);
8681
8682 /* reduce big weights */
8683 for( v = 0; v < vbig; ++v )
8684 {
8685 if( weights[v] > newweight )
8686 {
8687 consdataChgWeight(consdata, v, newweight);
8688 ++(*nchgcoefs);
8689 }
8690 }
8691
8692 /* reduce small weights */
8693 for( ; v < nvars; ++v )
8694 {
8695 if( weights[v] > 1 )
8696 {
8697 consdataChgWeight(consdata, v, 1LL);
8698 ++(*nchgcoefs);
8699 }
8700 }
8701
8702 consdata->capacity = newweight;
8703
8704 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8705 * weight must not be sorted by their index
8706 */
8707#ifndef NDEBUG
8708 for( v = nvars - 1; v > 0; --v )
8709 assert(weights[v] <= weights[v-1]);
8710#endif
8711 return SCIP_OKAY;
8712 }
8713 }
8714
8715 /* case 3. */
8716
8717 dualcapacity = consdata->weightsum - capacity;
8718 reductionsum = 0;
8719 v = 0;
8720
8721 /* reduce big weights
8722 *
8723 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8724 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8725 * <=> x0 + x1 + x2 + x3 <= 3
8726 */
8727 while( weights[v] > dualcapacity )
8728 {
8729 reductionsum += (weights[v] - dualcapacity);
8730 consdataChgWeight(consdata, v, dualcapacity);
8731 ++v;
8732 assert(v < nvars);
8733 }
8734 (*nchgcoefs) += v;
8735
8736 /* skip weights equal to the dualcapacity, because we cannot change them */
8737 while( v < nvars && weights[v] == dualcapacity )
8738 ++v;
8739
8740 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8741 * after a possible removal of the last, redundant item
8742 *
8743 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8744 */
8745 if( v >= nvars - 1 )
8746 {
8747 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8748 if( v == nvars - 1 )
8749 {
8750 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8751 }
8752 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8754
8755 return SCIP_OKAY;
8756 }
8757 /* at least two items with weight smaller than the dual capacity */
8758 else
8759 {
8760 /* @todo generalize the following algorithm for more than two variables */
8761
8762 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8763 {
8764 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8765 * coefficients) of all or two variables of the rest
8766 *
8767 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8768 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8769 * <=> 2x1 + 2x2 + x3 + x4 <= 4
8770 *
8771 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8772 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8773 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8774 *
8775 */
8776 if( v > 0 && weights[nvars - 2] > 1 )
8777 {
8778 int ncoefchg = 0;
8779
8780 /* reduce all bigger weights */
8781 for( w = 0; w < v; ++w )
8782 {
8783 if( weights[w] > 2 )
8784 {
8785 consdataChgWeight(consdata, w, 2LL);
8786 ++ncoefchg;
8787 }
8788 else
8789 {
8790 assert(weights[0] == 2);
8791 assert(weights[v - 1] == 2);
8792 break;
8793 }
8794 }
8795
8796 /* reduce all smaller weights */
8797 for( w = v; w < nvars; ++w )
8798 {
8799 if( weights[w] > 1 )
8800 {
8801 consdataChgWeight(consdata, w, 1LL);
8802 ++ncoefchg;
8803 }
8804 }
8805 assert(ncoefchg > 0);
8806
8807 (*nchgcoefs) += ncoefchg;
8808
8809 /* correct the capacity */
8810 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8811 assert(consdata->capacity > 0);
8812 assert(weights[0] <= consdata->capacity);
8813 assert(consdata->weightsum > consdata->capacity);
8814 /* reset the reductionsum */
8815 reductionsum = 0;
8816 }
8817 else if( v == 0 )
8818 {
8819 assert(weights[nvars - 2] == 1);
8820 }
8821 }
8822 else
8823 {
8824 SCIP_Longint minweight = weights[nvars - 1];
8825 SCIP_Longint newweight = dualcapacity - minweight;
8826 SCIP_Longint restsumweights = 0;
8827 SCIP_Longint sumcoef;
8828 SCIP_Bool sumcoefcase = FALSE;
8829 int startv = v;
8830 int end;
8831 int k;
8832
8833 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8834
8835 /* reduce big weights of pairs that exceed the dualcapacity
8836 *
8837 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8838 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8839 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8840 */
8841 while( weights[v] > newweight )
8842 {
8843 reductionsum += (weights[v] - newweight);
8844 consdataChgWeight(consdata, v, newweight);
8845 ++v;
8846 assert(v < nvars);
8847 }
8848 (*nchgcoefs) += (v - startv);
8849
8850 /* skip equal weights */
8851 while( weights[v] == newweight )
8852 ++v;
8853
8854 if( v > 0 )
8855 {
8856 for( w = v; w < nvars; ++w )
8857 restsumweights += weights[w];
8858 }
8859 else
8860 restsumweights = consdata->weightsum;
8861
8862 if( restsumweights < dualcapacity )
8863 {
8864 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8865 *
8866 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8867 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8868 */
8869 if( startv == v )
8870 {
8871 /* remove redundant variables */
8872 for( w = nvars - 1; w >= v; --w )
8873 {
8874 SCIP_CALL( delCoefPos(scip, cons, v) );
8875 ++(*nchgcoefs);
8876 }
8877
8878#ifndef NDEBUG
8879 /* each coefficients should exceed the dualcapacity by itself */
8880 for( ; w >= 0; --w )
8881 assert(weights[w] == dualcapacity);
8882#endif
8883 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8884 * upgrade this constraint
8885 */
8886 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8888
8889 return SCIP_OKAY;
8890 }
8891
8892 /* special case where we have three different coefficient types
8893 *
8894 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8895 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8896 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8897 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8898 */
8899 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8900 {
8901 SCIP_Longint newcap;
8902
8903 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8904 for( w = nvars - 1; w >= v; --w )
8905 {
8906 if( weights[w] > 1 )
8907 {
8908 consdataChgWeight(consdata, w, 1LL);
8909 ++(*nchgcoefs);
8910 }
8911 }
8912
8913 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8914 * dualcapacity
8915 */
8916 newweight = (SCIP_Longint)nvars - v;
8917 assert(newweight > 1);
8918 for( ; w >= startv; --w )
8919 {
8920 if( weights[w] > newweight )
8921 {
8922 consdataChgWeight(consdata, w, newweight);
8923 ++(*nchgcoefs);
8924 }
8925 else
8926 assert(weights[w] == newweight);
8927 }
8928
8929 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8930 ++newweight;
8931 assert(newweight > 2);
8932 for( ; w >= 0; --w )
8933 {
8934 if( weights[w] > newweight )
8935 {
8936 consdataChgWeight(consdata, w, newweight);
8937 ++(*nchgcoefs);
8938 }
8939 else
8940 assert(weights[w] == newweight);
8941 }
8942
8943 /* update the capacity */
8944 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8945 if( consdata->capacity > newcap )
8946 {
8947 consdata->capacity = newcap;
8948 ++(*nchgsides);
8949 }
8950 else
8951 assert(consdata->capacity == newcap);
8952 }
8953 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8954
8955 /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8956 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8957
8958 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8959 * weight must not be sorted by their index
8960 */
8961#ifndef NDEBUG
8962 for( w = nvars - 1; w > 0; --w )
8963 assert(weights[w] <= weights[w - 1]);
8964#endif
8965 return SCIP_OKAY;
8966 }
8967
8968 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8969 end = nvars - 2;
8970 while( end >= 0 && weights[end] == weights[end + 1] )
8971 {
8972 assert(end >= v);
8973 --end;
8974 }
8975
8976 if( v >= end )
8977 goto TERMINATE;
8978
8979 end = nvars - 2;
8980
8981 /* can we stop early, another special reduction case might exist */
8982 if( 2 * weights[end] > dualcapacity )
8983 {
8984 restsumweights = 0;
8985
8986 /* determine capacity of the small items */
8987 for( w = end + 1; w < nvars; ++w )
8988 restsumweights += weights[w];
8989
8990 if( restsumweights * 2 <= dualcapacity )
8991 {
8992 /* check for further posssible reductions in the middle */
8993 while( v < end && restsumweights + weights[v] >= dualcapacity )
8994 ++v;
8995
8996 if( v >= end )
8997 goto TERMINATE;
8998
8999 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9000 if( (dualcapacity & 1) == 0 )
9001 {
9002 newweight = dualcapacity / 2;
9003
9004 /* set all middle coefficients */
9005 for( ; v <= end; ++v )
9006 {
9007 if( weights[v] > newweight )
9008 {
9009 reductionsum += (weights[v] - newweight);
9010 consdataChgWeight(consdata, v, newweight);
9011 ++(*nchgcoefs);
9012 }
9013 }
9014 }
9015 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9016 * other coefficients by 2
9017 */
9018 else
9019 {
9020 /* correct the reductionsum */
9021 reductionsum *= 2;
9022
9023 /* multiply big coefficients by 2 */
9024 for( w = 0; w < v; ++w )
9025 {
9026 consdataChgWeight(consdata, w, weights[w] * 2);
9027 }
9028
9029 newweight = dualcapacity;
9030 /* set all middle coefficients */
9031 for( ; v <= end; ++v )
9032 {
9033 reductionsum += (2 * weights[v] - newweight);
9034 consdataChgWeight(consdata, v, newweight);
9035 }
9036
9037 /* multiply small coefficients by 2 */
9038 for( w = end + 1; w < nvars; ++w )
9039 {
9040 consdataChgWeight(consdata, w, weights[w] * 2);
9041 }
9042 (*nchgcoefs) += nvars;
9043
9044 dualcapacity *= 2;
9045 consdata->capacity *= 2;
9046 ++(*nchgsides);
9047 }
9048 }
9049
9050 goto TERMINATE;
9051 }
9052
9053 /* further reductions using the next possible coefficient sum
9054 *
9055 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9056 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9057 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9058 */
9059 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9060 for( k = 0; k < 4; ++k )
9061 {
9062 /* determine next minimal coefficient sum */
9063 switch( k )
9064 {
9065 case 0:
9066 sumcoef = weights[nvars - 1] + weights[nvars - 2];
9067 break;
9068 case 1:
9069 assert(nvars >= 3);
9070 sumcoef = weights[nvars - 1] + weights[nvars - 3];
9071 break;
9072 case 2:
9073 assert(nvars >= 4);
9074 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9075 {
9076 sumcoefcase = TRUE;
9077 sumcoef = weights[nvars - 1] + weights[nvars - 4];
9078 }
9079 else
9080 {
9081 sumcoefcase = FALSE;
9082 sumcoef = weights[nvars - 2] + weights[nvars - 3];
9083 }
9084 break;
9085 case 3:
9086 assert(nvars >= 5);
9087 if( sumcoefcase )
9088 {
9089 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9090 }
9091 else
9092 {
9093 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9094 }
9095 break;
9096 default:
9097 return SCIP_ERROR;
9098 }
9099
9100 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9101 minweight = weights[end];
9102 while( minweight <= sumcoef )
9103 {
9104 newweight = dualcapacity - minweight;
9105 startv = v;
9106 assert(v < nvars);
9107
9108 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9109 /* shrink big coefficients */
9110 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9111 {
9112 reductionsum += (weights[v] - newweight);
9113 consdataChgWeight(consdata, v, newweight);
9114 ++v;
9115 assert(v < nvars);
9116 }
9117 (*nchgcoefs) += (v - startv);
9118
9119 /* skip unchangable weights */
9120 while( weights[v] + minweight == dualcapacity )
9121 {
9122 assert(v < nvars);
9123 ++v;
9124 }
9125
9126 --end;
9127 /* skip same end weights */
9128 while( end >= 0 && weights[end] == weights[end + 1] )
9129 --end;
9130
9131 if( v >= end )
9132 goto TERMINATE;
9133
9134 minweight = weights[end];
9135 }
9136
9137 if( v >= end )
9138 goto TERMINATE;
9139
9140 /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9141 if( sumcoef < minweight )
9142 {
9143 minweight = sumcoef;
9144 newweight = dualcapacity - minweight;
9145 startv = v;
9146 assert(v < nvars);
9147
9148 /* shrink big coefficients */
9149 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9150 {
9151 reductionsum += (weights[v] - newweight);
9152 consdataChgWeight(consdata, v, newweight);
9153 ++v;
9154 assert(v < nvars);
9155 }
9156 (*nchgcoefs) += (v - startv);
9157
9158 /* skip unchangable weights */
9159 while( weights[v] + minweight == dualcapacity )
9160 {
9161 assert(v < nvars);
9162 ++v;
9163 }
9164 }
9165
9166 if( v >= end )
9167 goto TERMINATE;
9168
9169 /* can we stop early, another special reduction case might exist */
9170 if( 2 * weights[end] > dualcapacity )
9171 {
9172 restsumweights = 0;
9173
9174 /* determine capacity of the small items */
9175 for( w = end + 1; w < nvars; ++w )
9176 restsumweights += weights[w];
9177
9178 if( restsumweights * 2 <= dualcapacity )
9179 {
9180 /* check for further posssible reductions in the middle */
9181 while( v < end && restsumweights + weights[v] >= dualcapacity )
9182 ++v;
9183
9184 if( v >= end )
9185 goto TERMINATE;
9186
9187 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9188 if( (dualcapacity & 1) == 0 )
9189 {
9190 newweight = dualcapacity / 2;
9191
9192 /* set all middle coefficients */
9193 for( ; v <= end; ++v )
9194 {
9195 if( weights[v] > newweight )
9196 {
9197 reductionsum += (weights[v] - newweight);
9198 consdataChgWeight(consdata, v, newweight);
9199 ++(*nchgcoefs);
9200 }
9201 }
9202 }
9203 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9204 * other coefficients by 2
9205 */
9206 else
9207 {
9208 /* correct the reductionsum */
9209 reductionsum *= 2;
9210
9211 /* multiply big coefficients by 2 */
9212 for( w = 0; w < v; ++w )
9213 {
9214 consdataChgWeight(consdata, w, weights[w] * 2);
9215 }
9216
9217 newweight = dualcapacity;
9218 /* set all middle coefficients */
9219 for( ; v <= end; ++v )
9220 {
9221 reductionsum += (2 * weights[v] - newweight);
9222 consdataChgWeight(consdata, v, newweight);
9223 }
9224
9225 /* multiply small coefficients by 2 */
9226 for( w = end + 1; w < nvars; ++w )
9227 {
9228 consdataChgWeight(consdata, w, weights[w] * 2);
9229 }
9230 (*nchgcoefs) += nvars;
9231
9232 dualcapacity *= 2;
9233 consdata->capacity *= 2;
9234 ++(*nchgsides);
9235 }
9236 }
9237
9238 goto TERMINATE;
9239 }
9240
9241 /* cannot tighten any further */
9242 if( 2 * sumcoef > dualcapacity )
9243 goto TERMINATE;
9244 }
9245 }
9246 }
9247
9248 TERMINATE:
9249 /* correct capacity */
9250 if( reductionsum > 0 )
9251 {
9252 assert(v > 0);
9253
9254 consdata->capacity -= reductionsum;
9255 ++(*nchgsides);
9256
9257 assert(consdata->weightsum - dualcapacity == consdata->capacity);
9258 }
9259 assert(weights[0] <= consdata->capacity);
9260
9261 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9262 * weight must not be sorted by their index
9263 */
9264#ifndef NDEBUG
9265 for( w = nvars - 1; w > 0; --w )
9266 assert(weights[w] <= weights[w - 1]);
9267#endif
9268
9269 if( oldnchgcoefs < *nchgcoefs )
9270 {
9271 assert(!SCIPconsIsDeleted(cons));
9272
9273 /* it might be that we can divide the weights by their greatest common divisor */
9274 normalizeWeights(cons, nchgcoefs, nchgsides);
9275 }
9276 else
9277 {
9278 assert(oldnchgcoefs == *nchgcoefs);
9279 assert(oldnchgsides == *nchgsides);
9280 }
9281
9282 return SCIP_OKAY;
9283}
9284
9285
9286/** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9287static
9289 SCIP* scip, /**< SCIP data structure */
9290 SCIP_CONS* cons, /**< knapsack constraint */
9291 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9292 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9293 int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9294 )
9295{
9296 SCIP_VAR** vars;
9297 SCIP_CONSDATA* consdata;
9298 SCIP_Longint* weights;
9299 SCIP_Longint capacity;
9300 SCIP_Bool infeasible;
9301 SCIP_Bool fixed;
9302 int nvars;
9303 int v;
9304
9305 assert(scip != NULL);
9306 assert(cons != NULL);
9307 assert(nfixedvars != NULL);
9308 assert(ndelconss != NULL);
9309 assert(nchgcoefs != NULL);
9310
9311 consdata = SCIPconsGetData(cons);
9312 assert(consdata != NULL);
9313
9314 nvars = consdata->nvars;
9315
9316 /* no variables left, then delete constraint */
9317 if( nvars == 0 )
9318 {
9319 assert(consdata->capacity >= 0);
9320
9321 SCIP_CALL( SCIPdelCons(scip, cons) );
9322 ++(*ndelconss);
9323
9324 return SCIP_OKAY;
9325 }
9326
9327 /* sort items */
9328 sortItems(consdata);
9329
9330 vars = consdata->vars;
9331 weights = consdata->weights;
9332 capacity = consdata->capacity;
9333 v = 0;
9334
9335 /* check for weights bigger than the capacity */
9336 while( v < nvars && weights[v] > capacity )
9337 {
9338 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9339 assert(!infeasible);
9340
9341 if( fixed )
9342 ++(*nfixedvars);
9343
9344 ++v;
9345 }
9346
9347 /* if we fixed at least one variable we need to delete them from the constraint */
9348 if( v > 0 )
9349 {
9350 if( v == nvars )
9351 {
9352 SCIP_CALL( SCIPdelCons(scip, cons) );
9353 ++(*ndelconss);
9354
9355 return SCIP_OKAY;
9356 }
9357
9358 /* delete all position from back to front */
9359 for( --v; v >= 0; --v )
9360 {
9361 SCIP_CALL( delCoefPos(scip, cons, v) );
9362 ++(*nchgcoefs);
9363 }
9364
9365 /* sort items again because of deletion */
9366 sortItems(consdata);
9367 assert(vars == consdata->vars);
9368 assert(weights == consdata->weights);
9369 }
9370 assert(consdata->sorted);
9371 assert(weights[0] <= capacity);
9372
9373 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9374 {
9375 SCIP_CALL( SCIPdelCons(scip, cons) );
9376 ++(*ndelconss);
9377 }
9378
9379 return SCIP_OKAY;
9380}
9381
9382
9383/** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9384 *
9385 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9386 *
9387 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9388 *
9389 * the above constraint can be changed to
9390 *
9391 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9392 *
9393 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9394 *
9395 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9396 *
9397 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9398 * constraint further, e.g.
9399 *
9400 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9401 * => 2x1 + x2 + x3 + x4 <= 2
9402 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9403 */
9404static
9406 SCIP* scip, /**< SCIP data structure */
9407 SCIP_CONS* cons, /**< knapsack constraint */
9408 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9409 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9410 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9411 int* nchgsides, /**< pointer to store the amount of changed sides */
9412 int* naddconss, /**< pointer to count number of added constraints */
9413 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9414 )
9415{
9416 SCIP_VAR** vars;
9417 SCIP_CONSDATA* consdata;
9418 SCIP_Longint* weights;
9419 SCIP_Longint restweight;
9420 SCIP_Longint newweight;
9421 SCIP_Longint weight;
9422 SCIP_Longint oldgcd;
9423 SCIP_Longint rest;
9424 SCIP_Longint gcd;
9425 int oldnchgcoefs; /* cppcheck-suppress unassignedVariable */
9426 int oldnchgsides; /* cppcheck-suppress unassignedVariable */
9427 int candpos;
9428 int candpos2;
9429 int offsetv;
9430 int nvars;
9431 int v;
9432
9433 assert(scip != NULL);
9434 assert(cons != NULL);
9435 assert(nfixedvars != NULL);
9436 assert(ndelconss != NULL);
9437 assert(nchgcoefs != NULL);
9438 assert(nchgsides != NULL);
9439 assert(naddconss != NULL);
9440 assert(cutoff != NULL);
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 */
9450 assert(consdata->merged);
9451 if( *cutoff )
9452 return SCIP_OKAY;
9453
9454 assert(consdata->capacity >= 0);
9455
9456 /* fix variables with big coefficients and remove redundant constraints, sort weights */
9457 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9458
9459 if( SCIPconsIsDeleted(cons) )
9460 return SCIP_OKAY;
9461
9462 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9463 {
9464 /* 1. dual weights tightening */
9465 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9466
9467 if( SCIPconsIsDeleted(cons) )
9468 return SCIP_OKAY;
9469 /* 2. delete redundant variables */
9470 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9471
9472 if( SCIPconsIsDeleted(cons) )
9473 return SCIP_OKAY;
9474 }
9475
9476 weights = consdata->weights;
9477 nvars = consdata->nvars;
9478
9479#ifndef NDEBUG
9480 /* constraint might not be sorted, but the weights are already sorted */
9481 for( v = nvars - 1; v > 0; --v )
9482 assert(weights[v] <= weights[v-1]);
9483#endif
9484
9485 /* determine greatest common divisor */
9486 gcd = weights[nvars - 1];
9487 for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9488 {
9489 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9490 }
9491
9492 /* divide the constraint by their greatest common divisor */
9493 if( gcd >= 2 )
9494 {
9495 for( v = nvars - 1; v >= 0; --v )
9496 {
9497 consdataChgWeight(consdata, v, weights[v]/gcd);
9498 }
9499 (*nchgcoefs) += nvars;
9500
9501 consdata->capacity /= gcd;
9502 (*nchgsides)++;
9503 }
9504 assert(consdata->nvars == nvars);
9505
9506 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9507 * must not be sorted by their index
9508 */
9509#ifndef NDEBUG
9510 for( v = nvars - 1; v > 0; --v )
9511 assert(weights[v] <= weights[v-1]);
9512#endif
9513
9514 /* 3. start gcd procedure for all variables */
9515 do
9516 {
9517 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9518 SCIPdebug( oldnchgsides = *nchgsides; )
9519
9520 vars = consdata->vars;
9521 weights = consdata->weights;
9522 nvars = consdata->nvars;
9523
9524 /* stop if we have two coefficients which are one in absolute value */
9525 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9526 return SCIP_OKAY;
9527
9528 v = 0;
9529 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9530 * gcd
9531 */
9532 while( weights[v] == consdata->capacity )
9533 {
9534 ++v;
9535 assert(v < nvars);
9536 }
9537
9538 /* all but one variable are as big as the capacity, this is handled elsewhere */
9539 if( v == nvars - 1 )
9540 return SCIP_OKAY;
9541
9542 offsetv = v;
9543
9544 gcd = -1;
9545 candpos = -1;
9546 candpos2 = -1;
9547
9548 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9549 * change the coefficient
9550 */
9551 for( v = nvars - 1; v >= offsetv; --v )
9552 {
9553 weight = weights[v];
9554 assert(weight >= 1);
9555
9556 oldgcd = gcd;
9557
9558 if( gcd == -1 )
9559 {
9560 gcd = weights[v];
9561 assert(gcd >= 1);
9562 }
9563 else
9564 {
9565 /* calculate greatest common divisor for all variables */
9566 gcd = SCIPcalcGreComDiv(gcd, weight);
9567 }
9568
9569 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9570 * can terminate
9571 */
9572 if( gcd == 1 )
9573 {
9574 /* found candidate */
9575 if( candpos == -1 )
9576 {
9577 gcd = oldgcd;
9578 candpos = v;
9579
9580 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9581 if( v == nvars - 2 )
9582 candpos2 = v + 1;
9583 }
9584 /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9585 else
9586 {
9587 if( candpos == v + 1 && candpos2 == v + 2 )
9588 {
9589 assert(candpos2 == nvars - 1);
9590
9591 /* take new candidates */
9592 candpos = candpos2;
9593
9594 /* recalculate gcd from scratch */
9595 gcd = weights[v+1];
9596 assert(gcd >= 1);
9597
9598 /* calculate greatest common divisor for variables */
9599 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9600 if( gcd == 1 )
9601 return SCIP_OKAY;
9602 }
9603 else
9604 /* cannot determine a possible coefficient for reduction */
9605 return SCIP_OKAY;
9606 }
9607 }
9608 }
9609 assert(gcd >= 2);
9610
9611 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9612 * further
9613 */
9614 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9615
9616 /* determine the remainder of the capacity and the gcd */
9617 rest = consdata->capacity % gcd;
9618 assert(rest >= 0);
9619 assert(rest < gcd);
9620
9621 if( candpos == -1 )
9622 {
9623 /* we assume that the constraint was normalized */
9624 assert(rest > 0);
9625
9626 /* replace old with new capacity */
9627 consdata->capacity -= rest;
9628 ++(*nchgsides);
9629
9630 /* replace old big coefficients with new capacity */
9631 for( v = 0; v < offsetv; ++v )
9632 {
9633 consdataChgWeight(consdata, v, consdata->capacity);
9634 }
9635
9636 *nchgcoefs += offsetv;
9637 goto CONTINUE;
9638 }
9639
9640 /* determine the remainder of the coefficient candidate and the gcd */
9641 restweight = weights[candpos] % gcd;
9642 assert(restweight >= 1);
9643 assert(restweight < gcd);
9644
9645 /* calculate new coefficient */
9646 if( restweight > rest )
9647 newweight = weights[candpos] - restweight + gcd;
9648 else
9649 newweight = weights[candpos] - restweight;
9650
9651 assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9652
9653 SCIPdebugMsg(scip, "gcd = %" SCIP_LONGINT_FORMAT ", rest = %" SCIP_LONGINT_FORMAT ", restweight = %" SCIP_LONGINT_FORMAT "; possible new weight of variable <%s> %" SCIP_LONGINT_FORMAT ", possible new capacity %" SCIP_LONGINT_FORMAT ", offset of coefficients as big as capacity %d\n", gcd, rest, restweight, SCIPvarGetName(vars[candpos]), newweight, consdata->capacity - rest, offsetv);
9654
9655 /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9656 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9657 */
9658 if( newweight == 0 && offsetv > 0 )
9659 return SCIP_OKAY;
9660
9661 if( rest > 0 )
9662 {
9663 /* replace old with new capacity */
9664 consdata->capacity -= rest;
9665 ++(*nchgsides);
9666
9667 /* replace old big coefficients with new capacity */
9668 for( v = 0; v < offsetv; ++v )
9669 {
9670 consdataChgWeight(consdata, v, consdata->capacity);
9671 }
9672
9673 *nchgcoefs += offsetv;
9674 }
9675
9676 if( newweight == 0 )
9677 {
9678 /* delete redundant coefficient */
9679 SCIP_CALL( delCoefPos(scip, cons, candpos) );
9680 assert(consdata->nvars == nvars - 1);
9681 --nvars;
9682 }
9683 else
9684 {
9685 /* replace old with new coefficient */
9686 consdataChgWeight(consdata, candpos, newweight);
9687 }
9688 ++(*nchgcoefs);
9689
9690 assert(consdata->vars == vars);
9691 assert(consdata->nvars == nvars);
9692 assert(consdata->weights == weights);
9693
9694 CONTINUE:
9695 /* now constraint can be normalized, dividing it by the gcd */
9696 for( v = nvars - 1; v >= 0; --v )
9697 {
9698 consdataChgWeight(consdata, v, weights[v]/gcd);
9699 }
9700 (*nchgcoefs) += nvars;
9701
9702 consdata->capacity /= gcd;
9703 ++(*nchgsides);
9704
9706
9707 SCIPdebugMsg(scip, "we did %d coefficient changes and %d side changes on constraint %s when applying one round of the gcd algorithm\n", *nchgcoefs - oldnchgcoefs, *nchgsides - oldnchgsides, SCIPconsGetName(cons));
9708 }
9709 while( nvars >= 2 );
9710
9711 return SCIP_OKAY;
9712}
9713
9714
9715/** inserts an element into the list of binary zero implications */
9716static
9718 SCIP* scip, /**< SCIP data structure */
9719 int** liftcands, /**< array of the lifting candidates */
9720 int* nliftcands, /**< number of lifting candidates */
9721 int** firstidxs, /**< array of first zeroitems indices */
9722 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9723 int** zeroitems, /**< pointer to zero items array */
9724 int** nextidxs, /**< pointer to array of next zeroitems indeces */
9725 int* zeroitemssize, /**< pointer to size of zero items array */
9726 int* nzeroitems, /**< pointer to length of zero items array */
9727 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9728 SCIP_Bool value, /**< value v of variable y in implication */
9729 int knapsackidx, /**< index of variable x in knapsack */
9730 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9731 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9732 )
9733{
9734 int nzeros;
9735
9736 assert(liftcands != NULL);
9737 assert(liftcands[value] != NULL);
9738 assert(nliftcands != NULL);
9739 assert(firstidxs != NULL);
9740 assert(firstidxs[value] != NULL);
9741 assert(zeroweightsums != NULL);
9742 assert(zeroweightsums[value] != NULL);
9743 assert(zeroitems != NULL);
9744 assert(nextidxs != NULL);
9745 assert(zeroitemssize != NULL);
9746 assert(nzeroitems != NULL);
9747 assert(*nzeroitems <= *zeroitemssize);
9748 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9749 assert(memlimitreached != NULL);
9750
9751 nzeros = *nzeroitems;
9752
9753 /* allocate enough memory */
9754 if( nzeros == *zeroitemssize )
9755 {
9756 /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9757 * this can be too huge - abort on memory limit
9758 */
9759 if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9760 {
9761 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9762 *zeroitemssize);
9763 *memlimitreached = TRUE;
9764 return SCIP_OKAY;
9765 }
9766 *zeroitemssize *= 2;
9767 *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9768 SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9769 SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9770 }
9771 assert(nzeros < *zeroitemssize);
9772
9773 if( *memlimitreached )
9774 *memlimitreached = FALSE;
9775
9776 /* insert element */
9777 (*zeroitems)[nzeros] = knapsackidx;
9778 (*nextidxs)[nzeros] = firstidxs[value][probindex];
9779 if( firstidxs[value][probindex] == 0 )
9780 {
9781 liftcands[value][nliftcands[value]] = probindex;
9782 ++nliftcands[value];
9783 }
9784 firstidxs[value][probindex] = nzeros;
9785 ++(*nzeroitems);
9786 zeroweightsums[value][probindex] += knapsackweight;
9787
9788 return SCIP_OKAY;
9789}
9790
9791#define MAX_CLIQUELENGTH 50
9792/** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9793 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9794 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9795 * if cliqueweightsum(xi == v) < capacity:
9796 * - fixing variable xi to v would make the knapsack constraint redundant
9797 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9798 * redundancy effect:
9799 * wi' := capacity - cliqueweightsum(xi == v)
9800 * this rule can also be applied to binary variables not in the knapsack!
9801 */
9802static
9804 SCIP* scip, /**< SCIP data structure */
9805 SCIP_CONS* cons, /**< knapsack constraint */
9806 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9807 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9808 )
9809{
9810 SCIP_CONSDATA* consdata;
9811 SCIP_VAR** binvars;
9812 int nbinvars;
9813 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9814 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9815 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9816 int* zeroitems; /* item number in knapsack that is implied to zero */
9817 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9818 int zeroitemssize;
9819 int nzeroitems;
9820 SCIP_Bool* zeroiteminserted[2];
9821 SCIP_Bool memlimitreached;
9822 int nliftcands[2];
9823 SCIP_Bool* cliqueused;
9824 SCIP_Bool* itemremoved;
9825 SCIP_Longint maxcliqueweightsum;
9826 SCIP_VAR** addvars;
9827 SCIP_Longint* addweights;
9828 SCIP_Longint addweightsum;
9829 int nvars;
9830 int cliquenum;
9831 int naddvars;
9832 int val;
9833 int i;
9834
9835 int* tmpindices;
9836 SCIP_Bool* tmpboolindices;
9837 int* tmpindices2;
9838 SCIP_Bool* tmpboolindices2;
9839 int* tmpindices3;
9840 SCIP_Bool* tmpboolindices3;
9841 int tmp;
9842 int tmp2;
9843 int tmp3;
9844 SCIP_CONSHDLR* conshdlr;
9845 SCIP_CONSHDLRDATA* conshdlrdata;
9846
9847 assert(nchgcoefs != NULL);
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;
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 {
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 */
10302 }
10303
10304 /* free temporary memory */
10305 SCIPfreeBufferArray(scip, &addweights);
10306 SCIPfreeBufferArray(scip, &addvars);
10307 SCIPfreeBufferArray(scip, &tmpindices);
10308 SCIPfreeBufferArray(scip, &tmpindices2);
10309 SCIPfreeBufferArray(scip, &tmpindices3);
10310 SCIPfreeBufferArray(scip, &tmpboolindices2);
10311 SCIPfreeBufferArray(scip, &tmpboolindices3);
10312 SCIPfreeBufferArray(scip, &nextidxs);
10313 SCIPfreeBufferArray(scip, &zeroitems);
10314 SCIPfreeBufferArray(scip, &liftcands[1]);
10315 SCIPfreeBufferArray(scip, &liftcands[0]);
10316
10317 return SCIP_OKAY;
10318}
10319
10320/** tightens item weights and capacity in presolving:
10321 * given a knapsack sum(wi*xi) <= capacity
10322 * (1) let weightsum := sum(wi)
10323 * if weightsum - wi < capacity:
10324 * - not using item i would make the knapsack constraint redundant
10325 * - wi and capacity can be changed to have the same redundancy effect and the same results for
10326 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10327 * - change coefficients:
10328 * wi' := weightsum - capacity
10329 * capacity' := capacity - (wi - wi')
10330 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10331 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10332 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10333 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10334 * can be multiple times the same weight, this can be improved
10335 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10336 * weight, to capacity - lastmininmalweightsum, e.g. :
10337 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10338 * -> minimal weightsums: 5, 5, 10, 10
10339 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10340 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10341 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10342 * (3) let W(C) be the maximal weight of clique C,
10343 * cliqueweightsum := sum(W(C))
10344 * if cliqueweightsum - W(C) < capacity:
10345 * - not using any item of C would make the knapsack constraint redundant
10346 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10347 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10348 * - change coefficients:
10349 * delta := capacity - (cliqueweightsum - W(C))
10350 * wi' := max(wi - delta, 0)
10351 * capacity' := capacity - delta
10352 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10353 * introduce infeasible solutions.
10354 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10355 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10356 * if cliqueweightsum(xi == v) < capacity:
10357 * - fixing variable xi to v would make the knapsack constraint redundant
10358 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10359 * redundancy effect:
10360 * wi' := capacity - cliqueweightsum(xi == v)
10361 * This rule can also be applied to binary variables not in the knapsack!
10362 * (5) if min{w} + wi > capacity:
10363 * - using item i would force to fix other items to zero
10364 * - wi can be increased to the capacity
10365 */
10366static
10368 SCIP* scip, /**< SCIP data structure */
10369 SCIP_CONS* cons, /**< knapsack constraint */
10370 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10371 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10372 int* nchgsides, /**< pointer to count number of side changes */
10373 int* naddconss, /**< pointer to count number of added constraints */
10374 int* ndelconss, /**< pointer to count number of deleted constraints */
10375 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10376 )
10377{
10378 SCIP_CONSHDLRDATA* conshdlrdata;
10379 SCIP_CONSDATA* consdata;
10380 SCIP_Longint* weights;
10381 SCIP_Longint sumcoef;
10382 SCIP_Longint capacity;
10383 SCIP_Longint newweight;
10384 SCIP_Longint maxweight;
10385 SCIP_Longint minweight;
10386 SCIP_Bool sumcoefcase = FALSE;
10387 int startpos;
10388 int backpos;
10389 int nvars;
10390 int pos;
10391 int k;
10392 int i;
10393
10394 assert(nchgcoefs != NULL);
10395 assert(nchgsides != NULL);
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
10409 if( *cutoff )
10410 return SCIP_OKAY;
10411
10412 /* apply rule (1) */
10413 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10414 {
10415 do
10416 {
10417 assert(consdata->merged);
10418
10419 /* sort items, s.t. the heaviest one is in the first position */
10420 sortItems(consdata);
10421
10422 for( i = 0; i < consdata->nvars; ++i )
10423 {
10424 SCIP_Longint weight;
10425
10426 weight = consdata->weights[i];
10427 if( consdata->weightsum - weight < consdata->capacity )
10428 {
10429 newweight = consdata->weightsum - consdata->capacity;
10430 consdataChgWeight(consdata, i, newweight);
10431 consdata->capacity -= (weight - newweight);
10432 (*nchgcoefs)++;
10433 (*nchgsides)++;
10434 assert(!consdata->sorted);
10435 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT ", capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10436 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10437 consdata->capacity + (weight-newweight), consdata->capacity);
10438 }
10439 else
10440 break;
10441 }
10442 }
10443 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10444 }
10445
10446 /* check for redundancy */
10447 if( consdata->weightsum <= consdata->capacity )
10448 return SCIP_OKAY;
10449
10450 pos = 0;
10451 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10452 ++pos;
10453
10454 sumcoef = 0;
10455 weights = consdata->weights;
10456 nvars = consdata->nvars;
10457 capacity = consdata->capacity;
10458
10459 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10460 pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10461 {
10462 /* further reductions using the next possible coefficient sum
10463 *
10464 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10465 */
10466 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10467 for( k = 0; k < 4; ++k )
10468 {
10469 newweight = capacity - sumcoef;
10470
10471 /* determine next minimal coefficient sum */
10472 switch( k )
10473 {
10474 case 0:
10475 sumcoef = weights[nvars - 1];
10476 backpos = nvars - 1;
10477 break;
10478 case 1:
10479 sumcoef = weights[nvars - 2];
10480 backpos = nvars - 2;
10481 break;
10482 case 2:
10483 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10484 {
10485 sumcoefcase = TRUE;
10486 sumcoef = weights[nvars - 3];
10487 backpos = nvars - 3;
10488 }
10489 else
10490 {
10491 sumcoefcase = FALSE;
10492 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10493 backpos = nvars - 2;
10494 }
10495 break;
10496 default:
10497 assert(k == 3);
10498 if( sumcoefcase )
10499 {
10500 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10501 {
10502 sumcoef = weights[nvars - 4];
10503 backpos = nvars - 4;
10504 }
10505 else
10506 {
10507 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10508 backpos = nvars - 2;
10509 }
10510 }
10511 else
10512 {
10513 sumcoef = weights[nvars - 3];
10514 backpos = nvars - 3;
10515 }
10516 break;
10517 }
10518
10519 if( backpos <= pos )
10520 break;
10521
10522 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10523 maxweight = weights[pos];
10524 startpos = pos;
10525 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10526 {
10527 assert(newweight > weights[pos]);
10528
10529 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10530 SCIPconsGetName(cons), maxweight, newweight);
10531
10532 consdataChgWeight(consdata, pos, newweight);
10533
10534 ++pos;
10535 assert(pos < nvars);
10536
10537 maxweight = weights[pos];
10538
10539 if( backpos <= pos )
10540 break;
10541 }
10542 (*nchgcoefs) += (pos - startpos);
10543
10544 /* skip unchangable weights */
10545 while( pos < nvars && weights[pos] + sumcoef == capacity )
10546 ++pos;
10547
10548 /* check special case were there is only one weight left to tighten
10549 *
10550 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10551 *
10552 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10553 *
10554 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10555 */
10556 if( pos + 1 == backpos && weights[pos] > sumcoef &&
10557 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10558 {
10559 newweight = capacity - sumcoef;
10560 assert(newweight > weights[pos]);
10561
10562 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10563 SCIPconsGetName(cons), maxweight, newweight);
10564
10565 consdataChgWeight(consdata, pos, newweight);
10566
10567 break;
10568 }
10569
10570 if( backpos <= pos )
10571 break;
10572 }
10573 }
10574
10575 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10576 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10577 {
10578 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0
10579 && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 && pos > 0
10580 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity
10581 && consdata->weights[pos - 1] == consdata->capacity
10582 && ( pos == consdata->nvars || consdata->weights[pos] == 1 ) )
10583 {
10584 SCIP_VAR** clqvars;
10585 SCIP_CONS* cliquecons;
10586 char name[SCIP_MAXSTRLEN];
10587 int* clqpart;
10588 int nclqvars;
10589 int nclq;
10590 int len;
10591 int c;
10592 int w;
10593
10594 assert(!SCIPconsIsDeleted(cons));
10595
10596 if( pos == consdata->nvars )
10597 {
10598 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10599
10600 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10604 SCIPconsIsStickingAtNode(cons)) );
10605
10606 /* add the upgraded constraint to the problem */
10607 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10608 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10609 ++(*naddconss);
10610
10611 /* delete old constraint */
10612 SCIP_CALL( SCIPdelCons(scip, cons) );
10613 ++(*ndelconss);
10614
10615 return SCIP_OKAY;
10616 }
10617
10618 len = consdata->nvars - pos;
10619
10620 /* allocate temporary memory */
10621 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10622
10623 /* calculate clique partition */
10624 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
10625 assert(nclq <= len);
10626
10627#ifndef NDEBUG
10628 /* clique numbers must be at least as high as the index */
10629 for( w = 0; w < nclq; ++w )
10630 assert(clqpart[w] <= w);
10631#endif
10632
10633 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10634
10635 /* allocate temporary memory */
10636 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10637
10638 /* copy corresponding variables with big coefficients */
10639 for( w = pos - 1; w >= 0; --w )
10640 clqvars[w] = consdata->vars[w];
10641
10642 /* create for each clique a set-packing constraint */
10643 for( c = 0; c < nclq; ++c )
10644 {
10645 nclqvars = pos;
10646
10647 for( w = c; w < len; ++w )
10648 {
10649 if( clqpart[w] == c )
10650 {
10651 assert(nclqvars < pos + len - nclq + 1);
10652 clqvars[nclqvars] = consdata->vars[w + pos];
10653 ++nclqvars;
10654 }
10655 }
10656
10657 assert(nclqvars > 1);
10658
10659 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10660 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10664 SCIPconsIsStickingAtNode(cons)) );
10665
10666 /* add the special constraint to the problem */
10667 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10668 SCIPdebugPrintCons(scip, cliquecons, NULL);
10669 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10670 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10671 ++(*naddconss);
10672 }
10673
10674 /* delete old constraint */
10675 SCIP_CALL( SCIPdelCons(scip, cons) );
10676 ++(*ndelconss);
10677
10678 SCIPfreeBufferArray(scip, &clqvars);
10679 SCIPfreeBufferArray(scip, &clqpart);
10680
10681 return SCIP_OKAY;
10682 }
10683 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10684 {
10685 SCIP_Longint* maxcliqueweights;
10686 SCIP_Longint* newweightvals;
10687 int* newweightidxs;
10688 SCIP_Longint cliqueweightsum;
10689
10690 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10691 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10692 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10693
10694 /* repeat as long as changes have been applied */
10695 do
10696 {
10697 int ncliques;
10698 int cliquenum;
10699 SCIP_Bool zeroweights;
10700
10701 assert(consdata->merged);
10702
10703 /* sort items, s.t. the heaviest one is in the first position */
10704 sortItems(consdata);
10705
10706 /* calculate a clique partition */
10707 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10708
10709 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10710 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10711 break;
10712
10713 /* calculate the maximal weight of the cliques and store the clique type */
10714 cliqueweightsum = 0;
10715 ncliques = 0;
10716
10717 for( i = 0; i < consdata->nvars; ++i )
10718 {
10719 SCIP_Longint weight;
10720
10721 cliquenum = consdata->cliquepartition[i];
10722 assert(0 <= cliquenum && cliquenum <= ncliques);
10723
10724 weight = consdata->weights[i];
10725 assert(weight > 0);
10726
10727 if( cliquenum == ncliques )
10728 {
10729 maxcliqueweights[ncliques] = weight;
10730 cliqueweightsum += weight;
10731 ++ncliques;
10732 }
10733
10734 assert(maxcliqueweights[cliquenum] >= weight);
10735 }
10736
10737 /* apply rule on every clique */
10738 zeroweights = FALSE;
10739 for( i = 0; i < ncliques; ++i )
10740 {
10741 SCIP_Longint delta;
10742
10743 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10744 if( delta > 0 )
10745 {
10746 SCIP_Longint newcapacity;
10747#ifndef NDEBUG
10748 SCIP_Longint newmincliqueweight;
10749#endif
10750 SCIP_Longint newminweightsuminclique;
10751 SCIP_Bool forceclique;
10752 int nnewweights;
10753 int j;
10754
10755 SCIPdebugMsg(scip, "knapsack constraint <%s>: weights of clique %d (maxweight: %" SCIP_LONGINT_FORMAT ") can be tightened: cliqueweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT " -> delta: %" SCIP_LONGINT_FORMAT "\n",
10756 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10757 newcapacity = consdata->capacity - delta;
10758 forceclique = FALSE;
10759 nnewweights = 0;
10760#ifndef NDEBUG
10761 newmincliqueweight = newcapacity + 1;
10762 for( j = 0; j < i; ++j )
10763 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10764#endif
10765 for( j = i; j < consdata->nvars; ++j )
10766 {
10767 if( consdata->cliquepartition[j] == i )
10768 {
10769 newweight = consdata->weights[j] - delta;
10770 newweight = MAX(newweight, 0);
10771
10772 /* cache the new weight */
10773 assert(nnewweights < consdata->nvars);
10774 newweightvals[nnewweights] = newweight;
10775 newweightidxs[nnewweights] = j;
10776 nnewweights++;
10777
10778#ifndef NDEBUG
10779 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10780 newmincliqueweight = newweight;
10781#endif
10782 }
10783 }
10784
10785 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10786 if( nnewweights > 1 )
10787 {
10788#ifndef NDEBUG
10789 j = newweightidxs[nnewweights - 2];
10790 assert(0 <= j && j < consdata->nvars);
10791 assert(consdata->cliquepartition[j] == i);
10792 j = newweightidxs[nnewweights - 1];
10793 assert(0 <= j && j < consdata->nvars);
10794 assert(consdata->cliquepartition[j] == i);
10795#endif
10796
10797 newminweightsuminclique = newweightvals[nnewweights - 2];
10798 newminweightsuminclique += newweightvals[nnewweights - 1];
10799
10800 /* check if these new two minimal weights both fit into the knapsack;
10801 * if this is true, we have to add a clique constraint in order to enforce the clique
10802 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10803 * reduction might be infeasible, i.e., allows additional solutions)
10804 */
10805 if( newminweightsuminclique <= newcapacity )
10806 forceclique = TRUE;
10807 }
10808
10809 /* check if we really want to apply the change */
10810 if( conshdlrdata->disaggregation || !forceclique )
10811 {
10812 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10813 consdata->capacity, newcapacity, forceclique);
10814 consdata->capacity = newcapacity;
10815 (*nchgsides)++;
10816
10817 for( k = 0; k < nnewweights; ++k )
10818 {
10819 j = newweightidxs[k];
10820 assert(0 <= j && j < consdata->nvars);
10821 assert(consdata->cliquepartition[j] == i);
10822
10823 /* apply the weight change */
10824 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10825 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10826 consdataChgWeight(consdata, j, newweightvals[k]);
10827 (*nchgcoefs)++;
10828 assert(!consdata->sorted);
10829 zeroweights = zeroweights || (newweightvals[k] == 0);
10830 }
10831 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10832 * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10833 * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10834 * knapsack constraint
10835 */
10836 if( forceclique )
10837 {
10838 SCIP_CONS* cliquecons;
10839 char name[SCIP_MAXSTRLEN];
10840 SCIP_VAR** cliquevars;
10841
10842 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10843 for( k = 0; k < nnewweights; ++k )
10844 cliquevars[k] = consdata->vars[newweightidxs[k]];
10845
10846 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10847 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10851 SCIPconsIsStickingAtNode(cons)) );
10852
10853 /* add the special constraint to the problem */
10854 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10855 SCIPdebugPrintCons(scip, cliquecons, NULL);
10856 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10857 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10858 ++(*naddconss);
10859
10860 /* free clique array */
10861 SCIPfreeBufferArray(scip, &cliquevars);
10862 }
10863 }
10864 }
10865 }
10866 if( zeroweights )
10867 {
10869 }
10870 }
10871 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10872
10873 /* free temporary memory */
10874 SCIPfreeBufferArray(scip, &newweightidxs);
10875 SCIPfreeBufferArray(scip, &newweightvals);
10876 SCIPfreeBufferArray(scip, &maxcliqueweights);
10877
10878 /* check for redundancy */
10879 if( consdata->weightsum <= consdata->capacity )
10880 return SCIP_OKAY;
10881 }
10882 }
10883
10884 /* apply rule (3) */
10885 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10886 {
10887 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10888 }
10889
10890 /* check for redundancy */
10891 if( consdata->weightsum <= consdata->capacity )
10892 return SCIP_OKAY;
10893
10894 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10895 {
10896 /* apply rule (4) (all but smallest weight) */
10897 assert(consdata->merged);
10898 sortItems(consdata);
10899 minweight = consdata->weights[consdata->nvars-1];
10900 for( i = 0; i < consdata->nvars-1; ++i )
10901 {
10902 SCIP_Longint weight;
10903
10904 weight = consdata->weights[i];
10905 assert(weight >= minweight);
10906 if( minweight + weight > consdata->capacity )
10907 {
10908 if( weight < consdata->capacity )
10909 {
10910 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10911 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10912 assert(consdata->sorted);
10913 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10914 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10915 consdata->sorted = TRUE;
10916 (*nchgcoefs)++;
10917 }
10918 }
10919 else
10920 break;
10921 }
10922
10923 /* apply rule (5) (smallest weight) */
10924 if( consdata->nvars >= 2 )
10925 {
10926 SCIP_Longint weight;
10927
10928 minweight = consdata->weights[consdata->nvars-2];
10929 weight = consdata->weights[consdata->nvars-1];
10930 assert(minweight >= weight);
10931 if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10932 {
10933 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10934 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10935 assert(consdata->sorted);
10936 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10937 assert(minweight >= consdata->weights[consdata->nvars-1]);
10938 consdata->sorted = TRUE;
10939 (*nchgcoefs)++;
10940 }
10941 }
10942 }
10943
10944 return SCIP_OKAY;
10945}
10946
10947
10948#ifdef SCIP_DEBUG
10949static
10950void printClique(
10951 SCIP_VAR** cliquevars,
10952 int ncliquevars
10953 )
10954{
10955 int b;
10956 SCIPdebugMessage("adding new Clique: ");
10957 for( b = 0; b < ncliquevars; ++b )
10958 SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10959 SCIPdebugPrintf("\n");
10960}
10961#endif
10962
10963/** adds negated cliques of the knapsack constraint to the global clique table */
10964static
10966 SCIP*const scip, /**< SCIP data structure */
10967 SCIP_CONS*const cons, /**< knapsack constraint */
10968 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10969 int*const nbdchgs /**< pointer to count the number of performed bound changes */
10970 )
10971{
10972 SCIP_CONSDATA* consdata;
10973 SCIP_CONSHDLRDATA* conshdlrdata;
10974 SCIP_VAR** poscliquevars;
10975 SCIP_VAR** cliquevars;
10976 SCIP_Longint* maxweights;
10977 SCIP_Longint* gainweights;
10978 int* gaincliquepartition;
10979 SCIP_Bool* cliqueused;
10980 SCIP_Longint minactduetonegcliques;
10981 SCIP_Longint freecapacity;
10982 SCIP_Longint lastweight;
10983 SCIP_Longint beforelastweight;
10984 int nposcliquevars;
10985 int ncliquevars;
10986 int nvars;
10987 int nnegcliques;
10988 int lastcliqueused;
10989 int thisnbdchgs;
10990 int v;
10991 int w;
10992
10993 assert(scip != NULL);
10994 assert(cons != NULL);
10995 assert(cutoff != NULL);
10996 assert(nbdchgs != NULL);
10997
10998 *cutoff = FALSE;
10999
11000 consdata = SCIPconsGetData(cons);
11001 assert(consdata != NULL);
11002
11003 nvars = consdata->nvars;
11004
11005 /* check whether the cliques have already been added */
11006 if( consdata->cliquesadded || nvars == 0 )
11007 return SCIP_OKAY;
11008
11009 /* make sure, the items are merged */
11011 if( *cutoff )
11012 return SCIP_OKAY;
11013
11014 /* make sure, items are sorted by non-increasing weight */
11015 sortItems(consdata);
11016
11017 assert(consdata->merged);
11018
11019 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11020 assert(conshdlrdata != NULL);
11021
11022 /* calculate a clique partition */
11023 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11024 nnegcliques = consdata->nnegcliques;
11025
11026 /* if we have no negated cliques, stop */
11027 if( nnegcliques == nvars )
11028 return SCIP_OKAY;
11029
11030 /* get temporary memory */
11031 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11032 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11033 SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11034 SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11035 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11036 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11037
11038 nnegcliques = 0;
11039 minactduetonegcliques = 0;
11040
11041 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11042 for( v = 0; v < nvars; ++v )
11043 {
11044 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11045 assert(consdata->weights[v] > 0);
11046
11047 if( consdata->negcliquepartition[v] == nnegcliques )
11048 {
11049 nnegcliques++;
11050 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11051 }
11052 else
11053 minactduetonegcliques += consdata->weights[v];
11054 }
11055
11056 nposcliquevars = 0;
11057
11058 /* add cliques, using negated cliques information */
11059 if( minactduetonegcliques > 0 )
11060 {
11061 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11062 freecapacity = consdata->capacity - minactduetonegcliques;
11063
11065 SCIPdebugMsg(scip, "Try to add negated cliques in knapsack constraint handler for constraint %s; capacity = %" SCIP_LONGINT_FORMAT ", minactivity(due to neg. cliques) = %" SCIP_LONGINT_FORMAT ", freecapacity = %" SCIP_LONGINT_FORMAT ".\n",
11066 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11067
11068 /* calculate possible gain by switching chosen items in negated cliques */
11069 for( v = 0; v < nvars; ++v )
11070 {
11071 if( !cliqueused[consdata->negcliquepartition[v]] )
11072 {
11073 cliqueused[consdata->negcliquepartition[v]] = TRUE;
11074 for( w = v + 1; w < nvars; ++w )
11075 {
11076 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11077 * weight[w] (which are both in a negated clique) */
11078 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11079 && consdata->weights[v] > consdata->weights[w] )
11080 {
11081 poscliquevars[nposcliquevars] = consdata->vars[w];
11082 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11083 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11084 ++nposcliquevars;
11085 }
11086 }
11087 }
11088 }
11089
11090 /* try to create negated cliques */
11091 if( nposcliquevars > 0 )
11092 {
11093 /* sort possible gain per substitution of the clique members */
11094 SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11095
11096 for( v = 0; v < nposcliquevars; ++v )
11097 {
11098 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11099 ncliquevars = 1;
11100 lastweight = gainweights[v];
11101 beforelastweight = -1;
11102 lastcliqueused = gaincliquepartition[v];
11103 /* clear cliqueused to get an unused array */
11104 BMSclearMemoryArray(cliqueused, nnegcliques);
11105 cliqueused[gaincliquepartition[v]] = TRUE;
11106
11107 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11108 * in the same negated clique and by taking two of them would exceed the free capacity */
11110 {
11111 beforelastweight = lastweight;
11112 lastweight = gainweights[w];
11113 lastcliqueused = gaincliquepartition[w];
11114 cliqueused[gaincliquepartition[w]] = TRUE;
11115 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11116 ++ncliquevars;
11117 }
11118
11119 if( ncliquevars > 1 )
11120 {
11121 SCIPdebug( printClique(cliquevars, ncliquevars) );
11122 assert(beforelastweight > 0);
11123 /* add the clique to the clique table */
11124 /* this really happens, e.g., on enigma.mps from the short test set */
11125 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11126 if( *cutoff )
11127 goto TERMINATE;
11128 *nbdchgs += thisnbdchgs;
11129
11130 /* reset last used clique to get slightly different cliques */
11131 cliqueused[lastcliqueused] = FALSE;
11132
11133 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11135 {
11136 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11137 SCIPdebug( printClique(cliquevars, ncliquevars) );
11138 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11139 if( *cutoff )
11140 goto TERMINATE;
11141 *nbdchgs += thisnbdchgs;
11142 }
11143 }
11144 }
11145 }
11146 }
11147
11148 TERMINATE:
11149 /* free temporary memory */
11150 SCIPfreeBufferArray(scip, &cliqueused);
11151 SCIPfreeBufferArray(scip, &maxweights);
11152 SCIPfreeBufferArray(scip, &gaincliquepartition);
11153 SCIPfreeBufferArray(scip, &gainweights);
11154 SCIPfreeBufferArray(scip, &cliquevars);
11155 SCIPfreeBufferArray(scip, &poscliquevars);
11156
11157 return SCIP_OKAY;
11158}
11159
11160/** greedy clique detection by considering weights and capacity
11161 *
11162 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11163 * 1) neighboring items which exceed the capacity together => one clique
11164 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11165 */
11166static
11168 SCIP*const scip, /**< SCIP data structure */
11169 SCIP_VAR** items, /**< array of variable items */
11170 SCIP_Longint* weights, /**< weights of the items */
11171 int nitems, /**< the number of items */
11172 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11173 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11174 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11175 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11176 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11177 )
11178{
11179 SCIP_Longint lastweight;
11180 int ncliquevars;
11181 int i;
11182 int thisnbdchgs;
11183
11184 if( nitems <= 1 )
11185 return SCIP_OKAY;
11186
11187 /* sort possible gain per substitution of the clique members */
11188 if( ! sorteditems )
11189 SCIPsortDownLongPtr(weights,(void**) items, nitems);
11190
11191 ncliquevars = 1;
11192 lastweight = weights[0];
11193
11194 /* taking these two weights together violates the knapsack => include into clique */
11195 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11196 {
11197 lastweight = weights[i];
11198 ++ncliquevars;
11199 }
11200
11201 if( ncliquevars > 1 )
11202 {
11203 SCIP_Longint compareweight;
11204 SCIP_VAR** cliquevars;
11205 int compareweightidx;
11206 int minclqsize;
11207 int nnzadded;
11208
11209 /* add the clique to the clique table */
11210 SCIPdebug( printClique(items, ncliquevars) );
11211 SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11212
11213 if( *cutoff )
11214 return SCIP_OKAY;
11215
11216 *nbdchgs += thisnbdchgs;
11217 nnzadded = ncliquevars;
11218
11219 /* no more cliques to be found (don't know if this can actually happen, since the knapsack could be replaced by a set-packing constraint)*/
11220 if( ncliquevars == nitems )
11221 return SCIP_OKAY;
11222
11223 /* copy items in order into buffer array and deduce more cliques */
11224 SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11225
11226 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11227 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11228 compareweightidx = ncliquevars - 2;
11229 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11230
11231 /* determine minimum clique size for the following loop */
11232 minclqsize = (int)(cliqueextractfactor * ncliquevars);
11233 minclqsize = MAX(minclqsize, 2);
11234
11235 /* loop over the remaining variables and the larger items of the first clique until we
11236 * find another clique or reach the size limit */
11237 while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11238 && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11239 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11240 )
11241 {
11242 compareweight = weights[compareweightidx];
11243 assert(compareweight > 0);
11244
11245 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11246 if( compareweight + weights[i] > capacity )
11247 {
11248 assert(compareweightidx == ncliquevars -2);
11249 cliquevars[ncliquevars - 1] = items[i];
11250 SCIPdebug( printClique(cliquevars, ncliquevars) );
11251 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11252
11253 nnzadded += ncliquevars;
11254
11255 /* stop when there is a cutoff */
11256 if( ! (*cutoff) )
11257 *nbdchgs += thisnbdchgs;
11258
11259 /* go to next smaller item */
11260 ++i;
11261 }
11262 else
11263 {
11264 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11265 compareweightidx--;
11266 ncliquevars --;
11267 }
11268 }
11269
11270 SCIPfreeBufferArray(scip, &cliquevars);
11271 }
11272
11273 return SCIP_OKAY;
11274}
11275
11276/** adds cliques of the knapsack constraint to the global clique table */
11277static
11279 SCIP*const scip, /**< SCIP data structure */
11280 SCIP_CONS*const cons, /**< knapsack constraint */
11281 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11282 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11283 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11284 )
11285{
11286 SCIP_CONSDATA* consdata;
11287 SCIP_CONSHDLRDATA* conshdlrdata;
11288 int i;
11289 SCIP_Longint minactduetonegcliques;
11290 SCIP_Longint freecapacity;
11291 int nnegcliques;
11292 int cliquenum;
11293 SCIP_VAR** poscliquevars;
11294 SCIP_Longint* gainweights;
11295 int nposcliquevars;
11296 SCIP_Longint* secondmaxweights;
11297 int nvars;
11298
11299 assert(scip != NULL);
11300 assert(cons != NULL);
11301 assert(cutoff != NULL);
11302 assert(nbdchgs != NULL);
11303
11304 *cutoff = FALSE;
11305
11306 consdata = SCIPconsGetData(cons);
11307 assert(consdata != NULL);
11308
11309 nvars = consdata->nvars;
11310
11311 /* check whether the cliques have already been added */
11312 if( consdata->cliquesadded || nvars == 0 )
11313 return SCIP_OKAY;
11314
11315 /* make sure, the items are merged */
11317 if( *cutoff )
11318 return SCIP_OKAY;
11319
11320 /* make sure, the items are sorted by non-increasing weight */
11321 sortItems(consdata);
11322
11323 assert(consdata->merged);
11324
11325 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11326 assert(conshdlrdata != NULL);
11327
11328 /* calculate a clique partition */
11329 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11330 nnegcliques = consdata->nnegcliques;
11331 assert(nnegcliques <= nvars);
11332
11333 /* get temporary memory */
11334 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11335 SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11336 BMSclearMemoryArray(gainweights, nvars);
11337 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11338 BMSclearMemoryArray(secondmaxweights, nnegcliques);
11339
11340 minactduetonegcliques = 0;
11341
11342 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11343 if( nnegcliques < nvars )
11344 {
11345 nnegcliques = 0;
11346
11347 for( i = 0; i < nvars; ++i )
11348 {
11349 SCIP_Longint weight;
11350
11351 cliquenum = consdata->negcliquepartition[i];
11352 assert(0 <= cliquenum && cliquenum <= nnegcliques);
11353
11354 weight = consdata->weights[i];
11355 assert(weight > 0);
11356
11357 if( cliquenum == nnegcliques )
11358 nnegcliques++;
11359 else
11360 {
11361 minactduetonegcliques += weight;
11362 if( secondmaxweights[cliquenum] == 0 )
11363 secondmaxweights[cliquenum] = weight;
11364 }
11365 }
11366 }
11367
11368 /* add cliques, using negated cliques information */
11369 if( minactduetonegcliques > 0 )
11370 {
11371 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11372 freecapacity = consdata->capacity - minactduetonegcliques;
11373
11375 SCIPdebugMsg(scip, "Try to add cliques in knapsack constraint handler for constraint %s; capacity = %" SCIP_LONGINT_FORMAT ", minactivity(due to neg. cliques) = %" SCIP_LONGINT_FORMAT ", freecapacity = %" SCIP_LONGINT_FORMAT ".\n",
11376 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11377
11378 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11379 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11380
11381 if( *cutoff )
11382 goto TERMINATE;
11383
11384 nposcliquevars = 0;
11385
11386 for( i = nvars - 1; i >= 0; --i )
11387 {
11388 /* if we would take the biggest weight instead of the second biggest */
11389 cliquenum = consdata->negcliquepartition[i];
11390 if( consdata->weights[i] > secondmaxweights[cliquenum] )
11391 {
11392 poscliquevars[nposcliquevars] = consdata->vars[i];
11393 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11394 ++nposcliquevars;
11395 }
11396 }
11397
11398 /* use the gain weights and free capacity to derive greedily cliques */
11399 if( nposcliquevars > 1 )
11400 {
11401 SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11402
11403 if( *cutoff )
11404 goto TERMINATE;
11405 }
11406 }
11407
11408 /* build cliques by using the items with the maximal weights */
11409 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11410
11411 TERMINATE:
11412 /* free temporary memory and mark the constraint */
11413 SCIPfreeBufferArray(scip, &secondmaxweights);
11414 SCIPfreeBufferArray(scip, &gainweights);
11415 SCIPfreeBufferArray(scip, &poscliquevars);
11416 consdata->cliquesadded = TRUE;
11417
11418 return SCIP_OKAY;
11419}
11420
11421
11422/** gets the key of the given element */
11423static
11424SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11425{ /*lint --e{715}*/
11426 /* the key is the element itself */
11427 return elem;
11428}
11429
11430/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11431 * same coefficients
11432 */
11433static
11434SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11435{
11436#ifndef NDEBUG
11437 SCIP* scip;
11438#endif
11439 SCIP_CONSDATA* consdata1;
11440 SCIP_CONSDATA* consdata2;
11441 int i;
11442
11443 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11444 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11445 assert(consdata1->sorted);
11446 assert(consdata2->sorted);
11447#ifndef NDEBUG
11448 scip = (SCIP*)userptr;
11449 assert(scip != NULL);
11450#endif
11451
11452 /* checks trivial case */
11453 if( consdata1->nvars != consdata2->nvars )
11454 return FALSE;
11455
11456 for( i = consdata1->nvars - 1; i >= 0; --i )
11457 {
11458 /* tests if variables are equal */
11459 if( consdata1->vars[i] != consdata2->vars[i] )
11460 {
11461 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11462 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11463 return FALSE;
11464 }
11465 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11466
11467 /* tests if weights are equal too */
11468 if( consdata1->weights[i] != consdata2->weights[i] )
11469 return FALSE;
11470 }
11471
11472 return TRUE;
11473}
11474
11475/** returns the hash value of the key */
11476static
11477SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11478{
11479#ifndef NDEBUG
11480 SCIP* scip;
11481#endif
11482 SCIP_CONSDATA* consdata;
11483 uint64_t firstweight;
11484 int minidx;
11485 int mididx;
11486 int maxidx;
11487
11488 consdata = SCIPconsGetData((SCIP_CONS*)key);
11489 assert(consdata != NULL);
11490 assert(consdata->nvars > 0);
11491
11492#ifndef NDEBUG
11493 scip = (SCIP*)userptr;
11494 assert(scip != NULL);
11495#endif
11496
11497 /* sorts the constraints */
11498 sortItems(consdata);
11499
11500 minidx = SCIPvarGetIndex(consdata->vars[0]);
11501 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11502 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11503 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11504
11505 /* hash value depends on vectors of variable indices */
11506 firstweight = (uint64_t)consdata->weights[0];
11507 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11508}
11509
11510/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11511 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11512 */
11513static
11515 SCIP* scip, /**< SCIP data structure */
11516 BMS_BLKMEM* blkmem, /**< block memory */
11517 SCIP_CONS** conss, /**< constraint set */
11518 int nconss, /**< number of constraints in constraint set */
11519 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11520 int* ndelconss /**< pointer to count number of deleted constraints */
11521 )
11522{
11523 SCIP_HASHTABLE* hashtable;
11524 int hashtablesize;
11525 int c;
11526
11527 assert(scip != NULL);
11528 assert(blkmem != NULL);
11529 assert(conss != NULL);
11530 assert(ndelconss != NULL);
11531
11532 /* create a hash table for the constraint set */
11533 hashtablesize = nconss;
11534 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11535 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11536 hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11537
11538 /* check all constraints in the given set for redundancy */
11539 for( c = nconss - 1; c >= 0; --c )
11540 {
11541 SCIP_CONS* cons0;
11542 SCIP_CONS* cons1;
11543 SCIP_CONSDATA* consdata0;
11544
11545 cons0 = conss[c];
11546
11547 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11548 continue;
11549
11550 consdata0 = SCIPconsGetData(cons0);
11551 assert(consdata0 != NULL);
11552 if( consdata0->nvars == 0 )
11553 {
11554 if( consdata0->capacity < 0 )
11555 {
11556 *cutoff = TRUE;
11557 goto TERMINATE;
11558 }
11559 else
11560 {
11561 SCIP_CALL( SCIPdelCons(scip, cons0) );
11562 ++(*ndelconss);
11563 continue;
11564 }
11565 }
11566
11567 /* get constraint from current hash table with same variables and same weights as cons0 */
11568 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11569
11570 if( cons1 != NULL )
11571 {
11572 SCIP_CONS* consstay;
11573 SCIP_CONS* consdel;
11574 SCIP_CONSDATA* consdata1;
11575
11576 assert(SCIPconsIsActive(cons1));
11578
11579 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11580 * delete old constraints afterwards
11581 */
11582 consdata1 = SCIPconsGetData(cons1);
11583
11584 assert(consdata1 != NULL);
11585 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11586
11587 assert(consdata0->sorted && consdata1->sorted);
11588 assert(consdata0->vars[0] == consdata1->vars[0]);
11589 assert(consdata0->weights[0] == consdata1->weights[0]);
11590
11591 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11592 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11593
11594 /* check which constraint has to stay; */
11595 if( consdata0->capacity < consdata1->capacity )
11596 {
11597 consstay = cons0;
11598 consdel = cons1;
11599
11600 /* exchange consdel with consstay in hashtable */
11601 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11602 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11603 }
11604 else
11605 {
11606 consstay = cons1;
11607 consdel = cons0;
11608 }
11609
11610 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11611 SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11612
11613 /* delete consdel */
11614 SCIP_CALL( SCIPdelCons(scip, consdel) );
11615 ++(*ndelconss);
11616
11617 assert(SCIPconsIsActive(consstay));
11618 }
11619 else
11620 {
11621 /* no such constraint in current hash table: insert cons0 into hash table */
11622 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11623 }
11624 }
11625
11626 TERMINATE:
11627 /* free hash table */
11628 SCIPhashtableFree(&hashtable);
11629
11630 return SCIP_OKAY;
11631}
11632
11633
11634/** compares constraint with all prior constraints for possible redundancy or aggregation,
11635 * and removes or changes constraint accordingly
11636 */
11637static
11639 SCIP* scip, /**< SCIP data structure */
11640 SCIP_CONS** conss, /**< constraint set */
11641 int firstchange, /**< first constraint that changed since last pair preprocessing round */
11642 int chkind, /**< index of constraint to check against all prior indices upto startind */
11643 int* ndelconss /**< pointer to count number of deleted constraints */
11644 )
11645{
11646 SCIP_CONS* cons0;
11647 SCIP_CONSDATA* consdata0;
11648 int c;
11649
11650 assert(scip != NULL);
11651 assert(conss != NULL);
11652 assert(firstchange <= chkind);
11653 assert(ndelconss != NULL);
11654
11655 /* get the constraint to be checked against all prior constraints */
11656 cons0 = conss[chkind];
11657 assert(cons0 != NULL);
11658 assert(SCIPconsIsActive(cons0));
11660
11661 consdata0 = SCIPconsGetData(cons0);
11662 assert(consdata0 != NULL);
11663 assert(consdata0->nvars >= 1);
11664 assert(consdata0->merged);
11665
11666 /* sort the constraint */
11667 sortItems(consdata0);
11668
11669 /* see #2970 */
11670 if( consdata0->capacity == 0 )
11671 return SCIP_OKAY;
11672
11673 /* check constraint against all prior constraints */
11674 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11675 {
11676 SCIP_CONS* cons1;
11677 SCIP_CONSDATA* consdata1;
11678 SCIP_Bool iscons0incons1contained;
11679 SCIP_Bool iscons1incons0contained;
11680 SCIP_Real quotient;
11681 int v;
11682 int v0;
11683 int v1;
11684
11685 cons1 = conss[c];
11686 assert(cons1 != NULL);
11687 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11688 continue;
11689
11690 consdata1 = SCIPconsGetData(cons1);
11691 assert(consdata1 != NULL);
11692
11693 /* if both constraints didn't change since last pair processing, we can ignore the pair */
11694 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11695 continue;
11696
11697 assert(consdata1->nvars >= 1);
11698 assert(consdata1->merged);
11699
11700 /* sort the constraint */
11701 sortItems(consdata1);
11702
11703 /* see #2970 */
11704 if( consdata1->capacity == 0 )
11705 continue;
11706
11707 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11708
11709 if( consdata0->nvars > consdata1->nvars )
11710 {
11711 iscons0incons1contained = FALSE;
11712 iscons1incons0contained = TRUE;
11713 v = consdata1->nvars - 1;
11714 }
11715 else if( consdata0->nvars < consdata1->nvars )
11716 {
11717 iscons0incons1contained = TRUE;
11718 iscons1incons0contained = FALSE;
11719 v = consdata0->nvars - 1;
11720 }
11721 else
11722 {
11723 iscons0incons1contained = TRUE;
11724 iscons1incons0contained = TRUE;
11725 v = consdata0->nvars - 1;
11726 }
11727
11728 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11729
11730 /* check consdata0 against consdata1:
11731 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11732 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11733 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11734 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11735 */
11736 v0 = consdata0->nvars - 1;
11737 v1 = consdata1->nvars - 1;
11738
11739 while( v >= 0 )
11740 {
11741 assert(iscons0incons1contained || iscons1incons0contained);
11742
11743 /* now there are more variables in cons1 left */
11744 if( v1 > v0 )
11745 {
11746 iscons1incons0contained = FALSE;
11747 if( !iscons0incons1contained )
11748 break;
11749 }
11750 /* now there are more variables in cons0 left */
11751 else if( v1 < v0 )
11752 {
11753 iscons0incons1contained = FALSE;
11754 if( !iscons1incons0contained )
11755 break;
11756 }
11757
11758 assert(v == v0 || v == v1);
11759 assert(v0 >= 0);
11760 assert(v1 >= 0);
11761
11762 /* both variables are the same */
11763 if( consdata0->vars[v0] == consdata1->vars[v1] )
11764 {
11765 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11766 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11767 {
11768 iscons1incons0contained = FALSE;
11769 if( !iscons0incons1contained )
11770 break;
11771 }
11772 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11773 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11774 {
11775 iscons0incons1contained = FALSE;
11776 if( !iscons1incons0contained )
11777 break;
11778 }
11779 --v0;
11780 --v1;
11781 --v;
11782 }
11783 else
11784 {
11785 /* both constraints have a variables which is not part of the other constraint, so stop */
11786 if( iscons0incons1contained && iscons1incons0contained )
11787 {
11788 iscons0incons1contained = FALSE;
11789 iscons1incons0contained = FALSE;
11790 break;
11791 }
11792 assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11793 assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11794 /* continue to the next variable */
11795 if( iscons0incons1contained )
11796 --v1;
11797 else
11798 --v0;
11799 }
11800 }
11801 /* neither one constraint was contained in another or we checked all variables of one constraint against the
11802 * other
11803 */
11804 assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11805
11806 if( iscons1incons0contained )
11807 {
11808 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11809 SCIPdebugPrintCons(scip, cons1, NULL);
11810
11811 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11812 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11813
11814 SCIP_CALL( SCIPdelCons(scip, cons1) );
11815 ++(*ndelconss);
11816 }
11817 else if( iscons0incons1contained )
11818 {
11819 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11820 SCIPdebugPrintCons(scip, cons0, NULL);
11821
11822 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11823 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11824
11825 SCIP_CALL( SCIPdelCons(scip, cons0) );
11826 ++(*ndelconss);
11827 break;
11828 }
11829 }
11830
11831 return SCIP_OKAY;
11832}
11833
11834/** helper function to enforce constraints */
11835static
11837 SCIP* scip, /**< SCIP data structure */
11838 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11839 SCIP_CONS** conss, /**< constraints to process */
11840 int nconss, /**< number of constraints */
11841 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11842 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11843 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11844 )
11845{
11846 SCIP_CONSHDLRDATA* conshdlrdata;
11847 SCIP_Bool violated;
11849 int maxncuts;
11850 int ncuts = 0;
11851 int i;
11852
11854
11855 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11856 sol == NULL ? "LP" : "relaxation");
11857
11858 /* get maximal number of cuts per round */
11859 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11860 assert(conshdlrdata != NULL);
11861 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11862
11863 /* search for violated useful knapsack constraints */
11864 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11865 {
11866 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11867 if( violated )
11868 {
11869 /* add knapsack constraint as LP row to the relaxation */
11870 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11871 ncuts++;
11872 }
11873 }
11874
11875 /* as long as no violations were found, search for violated obsolete knapsack constraints */
11876 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11877 {
11878 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11879 if( violated )
11880 {
11881 /* add knapsack constraint as LP row to the relaxation */
11882 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11883 ncuts++;
11884 }
11885 }
11886
11887 /* adjust the result code */
11888 if ( cutoff )
11890 else if ( ncuts > 0 )
11892
11893 return SCIP_OKAY;
11894}
11895
11896/*
11897 * Linear constraint upgrading
11898 */
11899
11900/** creates and captures a knapsack constraint out of a linear inequality */
11901static
11903 SCIP* scip, /**< SCIP data structure */
11904 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11905 const char* name, /**< name of constraint */
11906 int nvars, /**< number of variables in the constraint */
11907 SCIP_VAR** vars, /**< array with variables of constraint entries */
11908 SCIP_Real* vals, /**< array with inequality coefficients */
11909 SCIP_Real lhs, /**< left hand side of inequality */
11910 SCIP_Real rhs, /**< right hand side of inequality */
11911 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11912 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11913 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11914 * Usually set to TRUE. */
11915 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11916 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11917 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11918 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11919 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11920 * Usually set to TRUE. */
11921 SCIP_Bool local, /**< is constraint only valid locally?
11922 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11923 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11924 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11925 * adds coefficients to this constraint. */
11926 SCIP_Bool dynamic, /**< is constraint subject to aging?
11927 * Usually set to FALSE. Set to TRUE for own cuts which
11928 * are separated as constraints. */
11929 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11930 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11931 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11932 * if it may be moved to a more global node?
11933 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11934 )
11935{
11936 SCIP_VAR** transvars;
11937 SCIP_Longint* weights;
11938 SCIP_Longint capacity;
11939 SCIP_Longint weight;
11940 int mult;
11941 int v;
11942
11943 assert(nvars == 0 || vars != NULL);
11944 assert(nvars == 0 || vals != NULL);
11945 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11946
11947 /* get temporary memory */
11948 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11950
11951 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11952 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11953 */
11954 if( SCIPisInfinity(scip, rhs) )
11955 {
11956 mult = -1;
11957 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11958 }
11959 else
11960 {
11961 mult = +1;
11962 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11963 }
11964
11965 /* negate positive or negative variables */
11966 for( v = 0; v < nvars; ++v )
11967 {
11968 assert(SCIPisFeasIntegral(scip, vals[v]));
11969 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11970 if( weight > 0 )
11971 {
11972 transvars[v] = vars[v];
11973 weights[v] = weight;
11974 }
11975 else
11976 {
11977 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11978 weights[v] = -weight; /*lint !e2704*/
11979 capacity -= weight;
11980 }
11981 assert(transvars[v] != NULL);
11982 }
11983
11984 /* create the constraint */
11985 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11986 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11987
11988 /* free temporary memory */
11989 SCIPfreeBufferArray(scip, &weights);
11990 SCIPfreeBufferArray(scip, &transvars);
11991
11992 return SCIP_OKAY;
11993}
11994
11995/** tries to upgrade a linear constraint into a knapsack constraint */
11996static
11997SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11998{ /*lint --e{715}*/
11999 SCIP_Bool upgrade;
12000
12001 assert(upgdcons != NULL);
12002
12003 /* check, if linear constraint can be upgraded to a knapsack constraint
12004 * - all variables must be binary
12005 * - all coefficients must be integral
12006 * - exactly one of the sides must be infinite
12007 * note that this includes the case of negative capacity, which has been
12008 * observed to occur, e.g., when upgrading a conflict constraint
12009 */
12010 upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
12011 && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
12012 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
12013
12014 if( upgrade )
12015 {
12016 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12017
12018 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12020 SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
12025 }
12026
12027 return SCIP_OKAY;
12028}
12029
12030/** adds symmetry information of constraint to a symmetry detection graph */
12031static
12033 SCIP* scip, /**< SCIP pointer */
12034 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
12035 SCIP_CONS* cons, /**< constraint */
12036 SYM_GRAPH* graph, /**< symmetry detection graph */
12037 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
12038 )
12039{
12040 SCIP_CONSDATA* consdata;
12041 SCIP_VAR** vars;
12042 SCIP_Real* vals;
12043 SCIP_Real constant = 0.0;
12044 SCIP_Real rhs;
12045 int nlocvars;
12046 int nvars;
12047 int i;
12048
12049 assert(scip != NULL);
12050 assert(cons != NULL);
12051 assert(graph != NULL);
12052 assert(success != NULL);
12053
12054 consdata = SCIPconsGetData(cons);
12055 assert(consdata != NULL);
12056 assert(graph != NULL);
12057
12058 /* get active variables of the constraint */
12060 nlocvars = consdata->nvars;
12061
12064
12065 for( i = 0; i < consdata->nvars; ++i )
12066 {
12067 vars[i] = consdata->vars[i];
12068 vals[i] = (SCIP_Real) consdata->weights[i];
12069 }
12070
12071 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
12072 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
12073
12075 cons, -SCIPinfinity(scip), rhs, success) );
12076
12077 SCIPfreeBufferArray(scip, &vals);
12079
12080 return SCIP_OKAY;
12081}
12082
12083/*
12084 * Callback methods of constraint handler
12085 */
12086
12087/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12088/**! [SnippetConsCopyKnapsack] */
12089static
12090SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12091{ /*lint --e{715}*/
12092 assert(scip != NULL);
12093 assert(conshdlr != NULL);
12094 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12095
12096 /* call inclusion method of constraint handler */
12098
12099 *valid = TRUE;
12100
12101 return SCIP_OKAY;
12102}
12103/**! [SnippetConsCopyKnapsack] */
12104
12105/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12106/**! [SnippetConsFreeKnapsack] */
12107static
12108SCIP_DECL_CONSFREE(consFreeKnapsack)
12109{ /*lint --e{715}*/
12110 SCIP_CONSHDLRDATA* conshdlrdata;
12111
12112 /* free constraint handler data */
12113 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12114 assert(conshdlrdata != NULL);
12115
12116 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->probtoidxmap, conshdlrdata->probtoidxmapsize);
12117 SCIPfreeBlockMemory(scip, &conshdlrdata);
12118
12119 SCIPconshdlrSetData(conshdlr, NULL);
12120
12121 return SCIP_OKAY;
12122}
12123/**! [SnippetConsFreeKnapsack] */
12124
12125
12126/** initialization method of constraint handler (called after problem was transformed) */
12127static
12128SCIP_DECL_CONSINIT(consInitKnapsack)
12129{ /*lint --e{715}*/
12130 SCIP_CONSHDLRDATA* conshdlrdata;
12131 int nvars;
12132
12133 assert( scip != NULL );
12134 assert( conshdlr != NULL );
12135
12136 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12137 assert(conshdlrdata != NULL);
12138
12139 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12141
12142 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12143 conshdlrdata->reals1size = nvars;
12144
12145 return SCIP_OKAY;
12146}
12147
12148/** deinitialization method of constraint handler (called before transformed problem is freed) */
12149static
12150SCIP_DECL_CONSEXIT(consExitKnapsack)
12151{ /*lint --e{715}*/
12152 SCIP_CONSHDLRDATA* conshdlrdata;
12153
12154 assert( scip != NULL );
12155 assert( conshdlr != NULL );
12156
12157 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12158 assert(conshdlrdata != NULL);
12159
12160 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12161 conshdlrdata->reals1size = 0;
12162
12163 return SCIP_OKAY;
12164}
12165
12166
12167/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12168static
12169SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12170{ /*lint --e{715}*/
12171 SCIP_CONSHDLRDATA* conshdlrdata;
12172 int nvars;
12173
12174 assert(scip != NULL);
12175 assert(conshdlr != NULL);
12176 assert(nconss == 0 || conss != NULL);
12177
12178 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12179 assert(conshdlrdata != NULL);
12180
12181 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12183
12184 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12185 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12186 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12187 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12188 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12189 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12190 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12191 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12192
12193 conshdlrdata->ints1size = nvars;
12194 conshdlrdata->ints2size = nvars;
12195 conshdlrdata->longints1size = nvars;
12196 conshdlrdata->longints2size = nvars;
12197 conshdlrdata->bools1size = nvars;
12198 conshdlrdata->bools2size = nvars;
12199 conshdlrdata->bools3size = nvars;
12200 conshdlrdata->bools4size = nvars;
12201
12202#ifdef WITH_CARDINALITY_UPGRADE
12203 conshdlrdata->upgradedcard = FALSE;
12204#endif
12205
12206 return SCIP_OKAY;
12207}
12208
12209
12210/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12211static
12212SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12213{ /*lint --e{715}*/
12214 SCIP_CONSHDLRDATA* conshdlrdata;
12215 int c;
12216
12217 assert(scip != NULL);
12218 assert(conshdlr != NULL);
12219
12220 for( c = 0; c < nconss; ++c )
12221 {
12222 if( !SCIPconsIsDeleted(conss[c]) )
12223 {
12224 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12225 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12226 }
12227 }
12228
12229 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12230 assert(conshdlrdata != NULL);
12231
12232 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12233 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12234 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12235 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12236 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12237 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12238 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12239 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12240
12241 conshdlrdata->ints1size = 0;
12242 conshdlrdata->ints2size = 0;
12243 conshdlrdata->longints1size = 0;
12244 conshdlrdata->longints2size = 0;
12245 conshdlrdata->bools1size = 0;
12246 conshdlrdata->bools2size = 0;
12247 conshdlrdata->bools3size = 0;
12248 conshdlrdata->bools4size = 0;
12249
12250 return SCIP_OKAY;
12251}
12252
12253/** solving process initialization method of constraint handler */
12254static
12255SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12256{ /*lint --e{715}*/
12257 /* add nlrow representation to NLP, if NLP had been constructed */
12259 {
12260 int c;
12261 for( c = 0; c < nconss; ++c )
12262 {
12263 SCIP_CALL( addNlrow(scip, conss[c]) );
12264 }
12265 }
12266
12267 return SCIP_OKAY;
12268}
12269
12270/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12271static
12272SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12273{ /*lint --e{715}*/
12274 SCIP_CONSDATA* consdata;
12275 int c;
12276
12277 assert( scip != NULL );
12278
12279 /* release the rows and nlrows of all constraints */
12280 for( c = 0; c < nconss; ++c )
12281 {
12282 consdata = SCIPconsGetData(conss[c]);
12283 assert(consdata != NULL);
12284
12285 if( consdata->row != NULL )
12286 {
12287 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12288 }
12289
12290 if( consdata->nlrow != NULL )
12291 {
12292 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12293 }
12294 }
12295
12296 return SCIP_OKAY;
12297}
12298
12299/** frees specific constraint data */
12300static
12301SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12302{ /*lint --e{715}*/
12303 SCIP_CONSHDLRDATA* conshdlrdata;
12304
12305 assert(conshdlr != NULL);
12306 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12307
12308 /* get event handler */
12309 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12310 assert(conshdlrdata != NULL);
12311 assert(conshdlrdata->eventhdlr != NULL);
12312
12313 /* free knapsack constraint */
12314 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12315
12316 return SCIP_OKAY;
12317}
12318
12319/** transforms constraint data into data belonging to the transformed problem */
12320/**! [SnippetConsTransKnapsack]*/
12321static
12322SCIP_DECL_CONSTRANS(consTransKnapsack)
12323{ /*lint --e{715}*/
12324 SCIP_CONSHDLRDATA* conshdlrdata;
12325 SCIP_CONSDATA* sourcedata;
12326 SCIP_CONSDATA* targetdata;
12327
12328 assert(conshdlr != NULL);
12329 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12331 assert(sourcecons != NULL);
12332 assert(targetcons != NULL);
12333
12334 sourcedata = SCIPconsGetData(sourcecons);
12335 assert(sourcedata != NULL);
12336 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12337
12338 /* get event handler */
12339 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12340 assert(conshdlrdata != NULL);
12341 assert(conshdlrdata->eventhdlr != NULL);
12342
12343 /* create target constraint data */
12344 SCIP_CALL( consdataCreate(scip, &targetdata,
12345 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12346
12347 /* create target constraint */
12348 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12349 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12350 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12351 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12352 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12353
12354 /* catch events for variables */
12355 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12356
12357 return SCIP_OKAY;
12358}
12359/**! [SnippetConsTransKnapsack]*/
12360
12361/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12362static
12363SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12364{ /*lint --e{715}*/
12365 int i;
12366
12367 *infeasible = FALSE;
12368
12369 for( i = 0; i < nconss && !(*infeasible); i++ )
12370 {
12371 assert(SCIPconsIsInitial(conss[i]));
12372 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12373 }
12374
12375 return SCIP_OKAY;
12376}
12377
12378/** separation method of constraint handler for LP solutions */
12379static
12380SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12381{ /*lint --e{715}*/
12382 SCIP_CONSHDLRDATA* conshdlrdata;
12383 SCIP_Bool sepacardinality;
12385
12386 SCIP_Real loclowerbound;
12387 SCIP_Real glblowerbound;
12388 SCIP_Real cutoffbound;
12389 SCIP_Real maxbound;
12390
12391 int depth;
12392 int nrounds;
12393 int sepafreq;
12394 int sepacardfreq;
12395 int ncuts;
12396 int maxsepacuts;
12397 int i;
12398
12400
12401 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12402 assert(conshdlrdata != NULL);
12403
12405 nrounds = SCIPgetNSepaRounds(scip);
12406
12407 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12408 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12409
12410 /* only call the separator a given number of times at each node */
12411 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12412 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12413 return SCIP_OKAY;
12414
12415 /* check, if we should additionally separate knapsack cuts */
12416 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12417 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12418 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12419 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12420
12421 /* check dual bound to see if we want to produce knapsack cuts at this node */
12422 loclowerbound = SCIPgetLocalLowerbound(scip);
12423 glblowerbound = SCIPgetLowerbound(scip);
12424 cutoffbound = SCIPgetCutoffbound(scip);
12425 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12426 sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12427 sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12428
12429 /* get the maximal number of cuts allowed in a separation round */
12430 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12431
12433 ncuts = 0;
12434 cutoff = FALSE;
12435
12436 /* separate useful constraints */
12437 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12438 {
12439 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12440 }
12441
12442 /* adjust return value */
12443 if ( cutoff )
12445 else if ( ncuts > 0 )
12447
12448 return SCIP_OKAY;
12449}
12450
12451
12452/** separation method of constraint handler for arbitrary primal solutions */
12453static
12454SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12455{ /*lint --e{715}*/
12456 SCIP_CONSHDLRDATA* conshdlrdata;
12457 SCIP_Bool sepacardinality;
12459
12460 int depth;
12461 int nrounds;
12462 int sepafreq;
12463 int sepacardfreq;
12464 int ncuts;
12465 int maxsepacuts;
12466 int i;
12467
12469
12470 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12471 assert(conshdlrdata != NULL);
12472
12474 nrounds = SCIPgetNSepaRounds(scip);
12475
12476 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12477 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12478
12479 /* only call the separator a given number of times at each node */
12480 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12481 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12482 return SCIP_OKAY;
12483
12484 /* check, if we should additionally separate knapsack cuts */
12485 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12486 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12487 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12488 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12489
12490 /* get the maximal number of cuts allowed in a separation round */
12491 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12492
12494 ncuts = 0;
12495 cutoff = FALSE;
12496
12497 /* separate useful constraints */
12498 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12499 {
12500 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12501 }
12502
12503 /* adjust return value */
12504 if ( cutoff )
12506 else if( ncuts > 0 )
12508
12509 return SCIP_OKAY;
12510}
12511
12512/** constraint enforcing method of constraint handler for LP solutions */
12513static
12514SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12515{ /*lint --e{715}*/
12516 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12517
12518 return SCIP_OKAY;
12519}
12520
12521/** constraint enforcing method of constraint handler for relaxation solutions */
12522static
12523SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12524{ /*lint --e{715}*/
12525 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12526
12527 return SCIP_OKAY;
12528}
12529
12530/** constraint enforcing method of constraint handler for pseudo solutions */
12531static
12532SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12533{ /*lint --e{715}*/
12534 SCIP_Bool violated;
12535 int i;
12536
12537 for( i = 0; i < nconss; i++ )
12538 {
12539 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12540 if( violated )
12541 {
12543 return SCIP_OKAY;
12544 }
12545 }
12547
12548 return SCIP_OKAY;
12549}
12550
12551/** feasibility check method of constraint handler for integral solutions */
12552static
12553SCIP_DECL_CONSCHECK(consCheckKnapsack)
12554{ /*lint --e{715}*/
12555 SCIP_Bool violated;
12556 int i;
12557
12559
12560 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12561 {
12562 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12563 if( violated )
12565 }
12566
12567 return SCIP_OKAY;
12568}
12569
12570/** domain propagation method of constraint handler */
12571static
12572SCIP_DECL_CONSPROP(consPropKnapsack)
12573{ /*lint --e{715}*/
12574 SCIP_CONSHDLRDATA* conshdlrdata;
12576 SCIP_Bool redundant;
12577 SCIP_Bool inpresolve;
12578 int nfixedvars;
12579 int i;
12580
12581 cutoff = FALSE;
12582 nfixedvars = 0;
12583
12584 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12585 assert(conshdlrdata != NULL);
12586
12587 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12588 assert(!inpresolve || SCIPinProbing(scip));
12589
12590 /* process useful constraints */
12591 for( i = 0; i < nmarkedconss && !cutoff; i++ )
12592 {
12593 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12594 * otherwise the multi-aggregation should be resolved
12595 */
12596 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12597 continue;
12598#ifndef NDEBUG
12599 else
12600 assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12601#endif
12602
12603 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12604
12605 /* unmark the constraint to be propagated */
12607 }
12608
12609 /* adjust result code */
12610 if( cutoff )
12612 else if( nfixedvars > 0 )
12614 else
12616
12617 return SCIP_OKAY; /*lint !e438*/
12618}
12619
12620/** presolving method of constraint handler */
12621static
12622SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12623{ /*lint --e{574,715}*/
12624 SCIP_CONSHDLRDATA* conshdlrdata;
12625 SCIP_CONSDATA* consdata;
12626 SCIP_CONS* cons;
12628 SCIP_Bool redundant;
12629 SCIP_Bool success;
12630 int oldnfixedvars;
12631 int oldnchgbds;
12632 int oldndelconss;
12633 int oldnaddconss;
12634 int oldnchgcoefs;
12635 int oldnchgsides;
12636 int firstchange;
12637 int c;
12638 SCIP_Bool newchanges;
12639
12640 /* remember old preprocessing counters */
12641 cutoff = FALSE;
12642 oldnfixedvars = *nfixedvars;
12643 oldnchgbds = *nchgbds;
12644 oldndelconss = *ndelconss;
12645 oldnaddconss = *naddconss;
12646 oldnchgcoefs = *nchgcoefs;
12647 oldnchgsides = *nchgsides;
12648 firstchange = INT_MAX;
12649
12650 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12651
12652 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12653 assert(conshdlrdata != NULL);
12654
12655 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12656 {
12657 int thisnfixedvars;
12658 int thisnchgbds;
12659
12660 cons = conss[c];
12661 consdata = SCIPconsGetData(cons);
12662 assert(consdata != NULL);
12663
12664 /* update data structures */
12665 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12666 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12667 {
12668 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12669 if( cutoff )
12670 break;
12671 }
12672
12673 /* force presolving the constraint in the initial round */
12674 if( nrounds == 0 )
12675 consdata->presolvedtiming = 0;
12676 else if( consdata->presolvedtiming >= presoltiming )
12677 continue;
12678
12679 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12681 consdata->presolvedtiming = presoltiming;
12682
12683 thisnfixedvars = *nfixedvars;
12684 thisnchgbds = *nchgbds;
12685
12686 /* merge constraint, so propagation works better */
12687 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12688 if( cutoff )
12689 break;
12690
12691 /* add cliques in the knapsack to the clique table */
12692 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12693 {
12694 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12695 if( cutoff )
12696 break;
12697 }
12698
12699 /* propagate constraint */
12700 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12701 {
12702 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12703
12704 if( cutoff )
12705 break;
12706 if( redundant )
12707 {
12708 (*ndelconss)++;
12709 continue;
12710 }
12711 }
12712
12713 /* remove again all fixed variables, if further fixings were found */
12714 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12715 {
12716 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12717 if( cutoff )
12718 break;
12719
12720 thisnfixedvars = *nfixedvars;
12721 }
12722
12723 if( !SCIPconsIsModifiable(cons) )
12724 {
12725 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12726 if( consdata->weightsum <= consdata->capacity )
12727 {
12728 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12729 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12731 continue;
12732 }
12733
12734 /* divide weights by their greatest common divisor */
12735 normalizeWeights(cons, nchgcoefs, nchgsides);
12736
12737 /* try to simplify inequalities */
12738 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12739 {
12740 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12741 if( cutoff )
12742 break;
12743
12744 if( SCIPconsIsDeleted(cons) )
12745 continue;
12746
12747 /* remove again all fixed variables, if further fixings were found */
12748 if( *nfixedvars > thisnfixedvars )
12749 {
12750 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12751 if( cutoff )
12752 break;
12753 }
12754 }
12755
12756 /* tighten capacity and weights */
12757 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12758 if( cutoff )
12759 break;
12760
12761 if( SCIPconsIsActive(cons) )
12762 {
12763 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12764 {
12765 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12766 * dual reduction
12767 */
12768 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12769 if( redundant )
12770 continue;
12771 }
12772
12773 /* check if knapsack constraint is parallel to objective function */
12774 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12775 }
12776 }
12777 /* remember the first changed constraint to begin the next aggregation round with */
12778 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12779 firstchange = c;
12780 }
12781
12782 /* preprocess pairs of knapsack constraints */
12783 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12784 {
12785 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12786 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12787 }
12788
12789 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12790 success = TRUE;
12791 else
12792 success = FALSE;
12793
12794 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12795 {
12796 SCIP_Longint npaircomparisons;
12797
12798 npaircomparisons = 0;
12799 oldndelconss = *ndelconss;
12800 oldnchgsides = *nchgsides;
12801 oldnchgcoefs = *nchgcoefs;
12802
12803 for( c = firstchange; c < nconss && !SCIPisStopped(scip); ++c )
12804 {
12805 cons = conss[c];
12806 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12807 continue;
12808
12809 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12810
12811 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12812
12813 if( npaircomparisons > NMINCOMPARISONS )
12814 {
12815 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12816 success = TRUE;
12817 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12818 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12819 break;
12820 oldndelconss = *ndelconss;
12821 oldnchgsides = *nchgsides;
12822 oldnchgcoefs = *nchgcoefs;
12823 npaircomparisons = 0;
12824 }
12825 }
12826 }
12827#ifdef WITH_CARDINALITY_UPGRADE
12828 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12829 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12830 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12831 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12832 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12833 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12834 * as well, we better keep this code disabled. */
12835 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12836 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12837 {
12838 SCIP_HASHMAP* varhash;
12839 SCIP_VAR** cardvars;
12840 SCIP_Real* cardweights;
12841 int noldupgdconss;
12842 int nscipvars;
12843 int makeupgrade;
12844
12845 noldupgdconss = *nupgdconss;
12846 nscipvars = SCIPgetNVars(scip);
12847 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12848 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12849
12850 /* set up hash map */
12851 SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12852
12853 /* We loop through all cardinality constraints twice:
12854 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12855 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12856 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12857 * - Second, upgrade knapsack constraints to cardinality constraints. */
12858 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12859 {
12860 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12861 {
12862 SCIP_CONS* cardcons;
12863 SCIP_VAR** vars;
12864 SCIP_Longint* weights;
12865 int nvars;
12866 int v;
12867
12868 cons = conss[c];
12869 assert( cons != NULL );
12870
12871 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
12872 continue;
12873
12874 consdata = SCIPconsGetData(cons);
12875 assert( consdata != NULL );
12876
12877 nvars = consdata->nvars;
12878 vars = consdata->vars;
12879 weights = consdata->weights;
12880
12881 /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12882 * - all variables must be binary (always true)
12883 * - all coefficients must be 1.0
12884 * - the right hand side must be smaller than nvars
12885 */
12886 if ( consdata->capacity >= nvars )
12887 continue;
12888
12889 /* the weights are sorted: check first and last weight */
12890 assert( consdata->sorted );
12891 if ( weights[0] != 1 || weights[nvars-1] != 1 )
12892 continue;
12893
12894 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12895 for (v = 0; v < nvars; ++v)
12896 {
12897 SCIP_BOUNDTYPE* impltypes;
12898 SCIP_Real* implbounds;
12899 SCIP_VAR** implvars;
12900 SCIP_VAR* var;
12901 int nimpls;
12902 int j;
12903
12904 var = consdata->vars[v];
12905 assert( var != NULL );
12907
12908 /* ignore non-active variables */
12909 if ( ! SCIPvarIsActive(var) )
12910 break;
12911
12912 /* be sure that implication variable has zero objective */
12913 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12914 break;
12915
12916 nimpls = SCIPvarGetNImpls(var, FALSE);
12917 implvars = SCIPvarGetImplVars(var, FALSE);
12918 implbounds = SCIPvarGetImplBounds(var, FALSE);
12919 impltypes = SCIPvarGetImplTypes(var, FALSE);
12920
12921 for (j = 0; j < nimpls; ++j)
12922 {
12923 /* be sure that continuous variable is fixed to 0 */
12924 if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12925 continue;
12926
12927 /* cannot currently deal with nonzero fixings */
12928 if ( ! SCIPisZero(scip, implbounds[j]) )
12929 continue;
12930
12931 /* number of down locks should be one */
12933 continue;
12934
12935 cardvars[v] = implvars[j];
12936 cardweights[v] = (SCIP_Real) v;
12937
12938 break;
12939 }
12940
12941 /* found no variable upper bound candidate -> exit */
12942 if ( j >= nimpls )
12943 break;
12944 }
12945
12946 /* did not find fitting variable upper bound for some variable -> exit */
12947 if ( v < nvars )
12948 break;
12949
12950 /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12951 * in which the binary variable is involved in */
12952 if ( makeupgrade == 0 )
12953 {
12954 for (v = 0; v < nvars; ++v)
12955 {
12956 if ( SCIPhashmapExists(varhash, vars[v]) )
12957 {
12958 int image;
12959
12960 image = SCIPhashmapGetImageInt(varhash, vars[v]);
12961 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12962 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12963 }
12964 else
12965 {
12966 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12967 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12968 assert( SCIPhashmapExists(varhash, vars[v]) );
12969 }
12970 }
12971 }
12972 else
12973 {
12974 SCIP_CONS* origcons;
12975
12976 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12977 * knapsack constraint coincides with the number of variable up locks */
12978 for (v = 0; v < nvars; ++v)
12979 {
12980 assert( SCIPhashmapExists(varhash, vars[v]) );
12982 break;
12983 }
12984 if ( v < nvars )
12985 break;
12986
12987 /* store that we have upgraded */
12988 conshdlrdata->upgradedcard = TRUE;
12989
12990 /* at this point we found suitable variable upper bounds */
12991 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12992
12993 /* create cardinality constraint */
12994 assert( ! SCIPconsIsModifiable(cons) );
12995 SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12999#ifdef SCIP_DEBUG
13000 SCIPprintCons(scip, cons, NULL);
13001 SCIPinfoMessage(scip, NULL, "\n");
13002 SCIPprintCons(scip, cardcons, NULL);
13003 SCIPinfoMessage(scip, NULL, "\n");
13004#endif
13005 /* add the upgraded constraint to the problem */
13006 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &cardcons) );
13007 ++(*nupgdconss);
13008
13009 /* delete oknapsack constraint */
13010 SCIP_CALL( SCIPdelCons(scip, cons) );
13011 ++(*ndelconss);
13012
13013 /* We need to disable the original knapsack constraint, since it might happen that the binary variables
13014 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
13015 * although the cardinality constraint is satisfied. */
13016 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
13017 assert( origcons != NULL );
13018 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
13019
13020 for (v = 0; v < nvars; ++v)
13021 {
13022 int image;
13023
13024 assert ( SCIPhashmapExists(varhash, vars[v]) );
13025 image = SCIPhashmapGetImageInt(varhash, vars[v]);
13026 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
13027 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
13028 }
13029 }
13030 }
13031 }
13032 SCIPhashmapFree(&varhash);
13033 SCIPfreeBufferArray(scip, &cardweights);
13034 SCIPfreeBufferArray(scip, &cardvars);
13035
13036 if ( *nupgdconss > noldupgdconss )
13037 success = TRUE;
13038 }
13039#endif
13040
13041 if( cutoff )
13043 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
13045 else
13047
13048 return SCIP_OKAY;
13049}
13050
13051/** propagation conflict resolving method of constraint handler */
13052static
13053SCIP_DECL_CONSRESPROP(consRespropKnapsack)
13054{ /*lint --e{715}*/
13055 SCIP_CONSDATA* consdata;
13056 SCIP_Longint capsum;
13057 int i;
13058
13059 assert(result != NULL);
13060
13061 consdata = SCIPconsGetData(cons);
13062 assert(consdata != NULL);
13063
13064 /* check if we fixed a binary variable to one (due to negated clique) */
13065 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
13066 {
13067 for( i = 0; i < consdata->nvars; ++i )
13068 {
13069 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
13070 {
13071 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13072 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13073 break;
13074 }
13075 }
13077 }
13078 else
13079 {
13080 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13081 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13082 * knapsack constraint, see one above call of SCIPinferBinvarCons
13083 */
13084 if( inferinfo < 0 )
13085 capsum = 0;
13086 else
13087 {
13088 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13089 * inferinfo stores the position of the inference variable (but maybe the variables were re-sorted)
13090 */
13091 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13092 capsum = consdata->weights[inferinfo];
13093 else
13094 {
13095 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13096 {}
13098 capsum = consdata->weights[i];
13099 }
13100 }
13101
13102 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13103 * the capacity
13104 */
13105 if( capsum <= consdata->capacity )
13106 {
13107 for( i = 0; i < consdata->nvars; i++ )
13108 {
13109 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13110 {
13111 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13112 capsum += consdata->weights[i];
13113 if( capsum > consdata->capacity )
13114 break;
13115 }
13116 }
13117 }
13118 }
13119
13120 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13121 * to zero can included negated clique information. A negated clique means, that at most one of the clique
13122 * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13123 * used to fix variables to zero.
13124 *
13125 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13126 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13127 * one.
13128 */
13130
13131 return SCIP_OKAY;
13132}
13133
13134/** variable rounding lock method of constraint handler */
13135/**! [SnippetConsLockKnapsack] */
13136static
13137SCIP_DECL_CONSLOCK(consLockKnapsack)
13138{ /*lint --e{715}*/
13139 SCIP_CONSDATA* consdata;
13140 int i;
13141
13142 consdata = SCIPconsGetData(cons);
13143 assert(consdata != NULL);
13144
13145 for( i = 0; i < consdata->nvars; i++)
13146 {
13147 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13148 }
13149
13150 return SCIP_OKAY;
13151}
13152/**! [SnippetConsLockKnapsack] */
13153
13154/** constraint activation notification method of constraint handler */
13155static
13156SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13157{ /*lint --e{715}*/
13159 {
13160 SCIP_CALL( addNlrow(scip, cons) );
13161 }
13162
13163 return SCIP_OKAY;
13164}
13165
13166/** constraint deactivation notification method of constraint handler */
13167static
13168SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13169{ /*lint --e{715}*/
13170 SCIP_CONSDATA* consdata;
13171
13172 assert(cons != NULL);
13173
13174 consdata = SCIPconsGetData(cons);
13175 assert(consdata != NULL);
13176
13177 /* remove row from NLP, if still in solving
13178 * if we are in exitsolve, the whole NLP will be freed anyway
13179 */
13180 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13181 {
13182 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13183 }
13184
13185 return SCIP_OKAY;
13186}
13187
13188/** variable deletion method of constraint handler */
13189static
13190SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13191{
13192 assert(scip != NULL);
13193 assert(conshdlr != NULL);
13194 assert(conss != NULL || nconss == 0);
13195
13196 if( nconss > 0 )
13197 {
13198 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13199 }
13200
13201 return SCIP_OKAY;
13202}
13203
13204/** constraint display method of constraint handler */
13205static
13206SCIP_DECL_CONSPRINT(consPrintKnapsack)
13207{ /*lint --e{715}*/
13208 SCIP_CONSDATA* consdata;
13209 int i;
13210
13211 assert( scip != NULL );
13212 assert( conshdlr != NULL );
13213 assert( cons != NULL );
13214
13215 consdata = SCIPconsGetData(cons);
13216 assert(consdata != NULL);
13217
13218 for( i = 0; i < consdata->nvars; ++i )
13219 {
13220 if( i > 0 )
13221 SCIPinfoMessage(scip, file, " ");
13222 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13223 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13224 }
13225 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13226
13227 return SCIP_OKAY;
13228}
13229
13230/** constraint copying method of constraint handler */
13231static
13232SCIP_DECL_CONSCOPY(consCopyKnapsack)
13233{ /*lint --e{715}*/
13234 SCIP_VAR** sourcevars;
13235 SCIP_Longint* weights;
13236 SCIP_Real* coefs;
13237 const char* consname;
13238 int nvars;
13239 int v;
13240
13241 /* get variables and coefficients of the source constraint */
13242 sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13243 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13244 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13245
13247 for( v = 0; v < nvars; ++v )
13248 coefs[v] = (SCIP_Real) weights[v];
13249
13250 if( name != NULL )
13251 consname = name;
13252 else
13253 consname = SCIPconsGetName(sourcecons);
13254
13255 /* copy the logic using the linear constraint copy method */
13256 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13257 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13258 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13259 assert(cons != NULL);
13260
13261 SCIPfreeBufferArray(scip, &coefs);
13262
13263 return SCIP_OKAY;
13264}
13265
13266/** constraint parsing method of constraint handler */
13267static
13268SCIP_DECL_CONSPARSE(consParseKnapsack)
13269{ /*lint --e{715}*/
13270 SCIP_VAR* var;
13271 SCIP_Longint weight;
13272 SCIP_VAR** vars;
13273 SCIP_Longint* weights;
13274 SCIP_Longint capacity;
13275 char* endptr;
13276 int nread;
13277 int nvars;
13278 int varssize;
13279
13280 assert(scip != NULL);
13281 assert(success != NULL);
13282 assert(str != NULL);
13283 assert(name != NULL);
13284 assert(cons != NULL);
13285
13286 *success = TRUE;
13287
13288 nvars = 0;
13289 varssize = 5;
13290 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13291 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13292
13293 while( *str != '\0' )
13294 {
13295 /* try to parse coefficient, and use 1 if not successful */
13296 weight = 1;
13297 nread = 0;
13298 (void) sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13299 str += nread;
13300
13301 /* parse variable name */
13302 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13303
13304 if( var == NULL )
13305 {
13306 endptr = strchr(endptr, '<');
13307
13308 if( endptr == NULL )
13309 {
13310 SCIPerrorMessage("no capacity found\n");
13311 *success = FALSE;
13312 }
13313 else
13314 str = endptr;
13315
13316 break;
13317 }
13318
13319 str = endptr;
13320
13321 /* store weight and variable */
13322 if( varssize <= nvars )
13323 {
13324 varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13325 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13326 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13327 }
13328
13329 vars[nvars] = var;
13330 weights[nvars] = weight;
13331 ++nvars;
13332
13333 /* skip whitespace */
13334 SCIP_CALL( SCIPskipSpace((char**)&str) );
13335 }
13336
13337 if( *success )
13338 {
13339 if( strncmp(str, "<=", 2) != 0 )
13340 {
13341 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13342 *success = FALSE;
13343 }
13344 else
13345 {
13346 str += 2;
13347 }
13348 }
13349
13350 if( *success )
13351 {
13352 /* skip whitespace */
13353 SCIP_CALL( SCIPskipSpace((char**)&str) );
13354
13355 /* coverity[secure_coding] */
13356 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13357 {
13358 SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13359 *success = FALSE;
13360 }
13361 else
13362 {
13363 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13364 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13365 }
13366 }
13367
13369 SCIPfreeBufferArray(scip, &weights);
13370
13371 return SCIP_OKAY;
13372}
13373
13374/** constraint method of constraint handler which returns the variables (if possible) */
13375static
13376SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13377{ /*lint --e{715}*/
13378 SCIP_CONSDATA* consdata;
13379
13380 consdata = SCIPconsGetData(cons);
13381 assert(consdata != NULL);
13382
13383 if( varssize < consdata->nvars )
13384 (*success) = FALSE;
13385 else
13386 {
13387 assert(vars != NULL);
13388
13389 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13390 (*success) = TRUE;
13391 }
13392
13393 return SCIP_OKAY;
13394}
13395
13396/** constraint method of constraint handler which returns the number of variables (if possible) */
13397static
13398SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13399{ /*lint --e{715}*/
13400 SCIP_CONSDATA* consdata;
13401
13402 consdata = SCIPconsGetData(cons);
13403 assert(consdata != NULL);
13404
13405 (*nvars) = consdata->nvars;
13406 (*success) = TRUE;
13407
13408 return SCIP_OKAY;
13409}
13410
13411/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
13412static
13413SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
13414{ /*lint --e{715}*/
13415 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
13416
13417 return SCIP_OKAY;
13418}
13419
13420/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
13421static
13422SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
13423{ /*lint --e{715}*/
13424 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
13425
13426 return SCIP_OKAY;
13427}
13428
13429/*
13430 * Event handler
13431 */
13432
13433/** execution method of bound change event handler */
13434static
13435SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13436{ /*lint --e{715}*/
13437 SCIP_CONSDATA* consdata;
13438
13439 assert(eventdata != NULL);
13440 assert(eventdata->cons != NULL);
13441
13442 consdata = SCIPconsGetData(eventdata->cons);
13443 assert(consdata != NULL);
13444
13445 switch( SCIPeventGetType(event) )
13446 {
13448 consdata->onesweightsum += eventdata->weight;
13449 consdata->presolvedtiming = 0;
13450 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13451 break;
13453 consdata->onesweightsum -= eventdata->weight;
13454 break;
13456 consdata->presolvedtiming = 0;
13457 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13458 break;
13459 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13460 if( !consdata->existmultaggr )
13461 {
13462 SCIP_VAR* var;
13463 var = SCIPeventGetVar(event);
13464 assert(var != NULL);
13465
13466 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13468 {
13469 consdata->existmultaggr = TRUE;
13470 consdata->merged = FALSE;
13471 }
13474 consdata->merged = FALSE;
13475 }
13476 /*lint -fallthrough*/
13477 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13478 consdata->presolvedtiming = 0;
13479 break;
13481 consdata->varsdeleted = TRUE;
13482 break;
13483 default:
13484 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13485 return SCIP_INVALIDDATA;
13486 }
13487
13488 return SCIP_OKAY;
13489}
13490
13491
13492/*
13493 * constraint specific interface methods
13494 */
13495
13496/** creates the handler for knapsack constraints and includes it in SCIP */
13498 SCIP* scip /**< SCIP data structure */
13499 )
13500{
13501 SCIP_EVENTHDLRDATA* eventhdlrdata;
13502 SCIP_CONSHDLRDATA* conshdlrdata;
13503 SCIP_CONSHDLR* conshdlr;
13504
13505 /* create knapsack constraint handler data */
13506 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13507
13508 /* include event handler for bound change events */
13509 eventhdlrdata = NULL;
13510 conshdlrdata->eventhdlr = NULL;
13512 eventExecKnapsack, eventhdlrdata) );
13513 conshdlrdata->probtoidxmap = NULL;
13514 conshdlrdata->probtoidxmapsize = 0;
13515
13516 /* get event handler for bound change events */
13517 if( conshdlrdata->eventhdlr == NULL )
13518 {
13519 SCIPerrorMessage("event handler for knapsack constraints not found\n");
13520 return SCIP_PLUGINNOTFOUND;
13521 }
13522
13523 /* include constraint handler */
13526 consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13527 conshdlrdata) );
13528
13529 assert(conshdlr != NULL);
13530
13531 /* set non-fundamental callbacks via specific setter functions */
13532 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13533 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13534 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13535 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13536 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13537 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13538 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13539 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13540 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13541 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13542 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13543 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13544 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13545 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13546 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13547 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13549 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13552 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13553 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13555 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13556 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13557 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) );
13558 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) );
13559
13560 if( SCIPfindConshdlr(scip,"linear") != NULL )
13561 {
13562 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13564 }
13565
13566 /* add knapsack constraint handler parameters */
13568 "constraints/" CONSHDLR_NAME "/sepacardfreq",
13569 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13570 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13572 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13573 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13574 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13576 "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13577 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13578 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13580 "constraints/" CONSHDLR_NAME "/maxrounds",
13581 "maximal number of separation rounds per node (-1: unlimited)",
13582 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13584 "constraints/" CONSHDLR_NAME "/maxroundsroot",
13585 "maximal number of separation rounds per node in the root node (-1: unlimited)",
13586 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13588 "constraints/" CONSHDLR_NAME "/maxsepacuts",
13589 "maximal number of cuts separated per separation round",
13590 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13592 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13593 "maximal number of cuts separated per separation round in the root node",
13594 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13596 "constraints/" CONSHDLR_NAME "/disaggregation",
13597 "should disaggregation of knapsack constraints be allowed in preprocessing?",
13598 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13600 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13601 "should presolving try to simplify knapsacks",
13602 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13604 "constraints/" CONSHDLR_NAME "/negatedclique",
13605 "should negated clique information be used in solving process",
13606 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13608 "constraints/" CONSHDLR_NAME "/presolpairwise",
13609 "should pairwise constraint comparison be performed in presolving?",
13610 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13612 "constraints/" CONSHDLR_NAME "/presolusehashing",
13613 "should hash table be used for detecting redundant constraints in advance",
13614 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13616 "constraints/" CONSHDLR_NAME "/dualpresolving",
13617 "should dual presolving steps be performed?",
13618 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13620 "constraints/" CONSHDLR_NAME "/usegubs",
13621 "should GUB information be used for separation?",
13622 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13624 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13625 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13626 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13628 "constraints/" CONSHDLR_NAME "/detectlowerbound",
13629 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13630 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13632 "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13633 "should clique partition information be updated when old partition seems outdated?",
13634 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13636 "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13637 "factor on the growth of global cliques to decide when to update a previous "
13638 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13639 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13640#ifdef WITH_CARDINALITY_UPGRADE
13642 "constraints/" CONSHDLR_NAME "/upgdcardinality",
13643 "if TRUE then try to update knapsack constraints to cardinality constraints",
13644 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13645#endif
13646 return SCIP_OKAY;
13647}
13648
13649/** creates and captures a knapsack constraint
13650 *
13651 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13652 */
13653/**! [SnippetConsCreationKnapsack] */
13655 SCIP* scip, /**< SCIP data structure */
13656 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13657 const char* name, /**< name of constraint */
13658 int nvars, /**< number of items in the knapsack */
13659 SCIP_VAR** vars, /**< array with item variables */
13660 SCIP_Longint* weights, /**< array with item weights */
13661 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13662 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13663 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13664 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13665 * Usually set to TRUE. */
13666 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13667 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13668 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13669 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13670 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13671 * Usually set to TRUE. */
13672 SCIP_Bool local, /**< is constraint only valid locally?
13673 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13674 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13675 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13676 * adds coefficients to this constraint. */
13677 SCIP_Bool dynamic, /**< is constraint subject to aging?
13678 * Usually set to FALSE. Set to TRUE for own cuts which
13679 * are separated as constraints. */
13680 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13681 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13682 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13683 * if it may be moved to a more global node?
13684 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13685 )
13686{
13687 SCIP_CONSHDLRDATA* conshdlrdata;
13688 SCIP_CONSHDLR* conshdlr;
13689 SCIP_CONSDATA* consdata;
13690 int i;
13691
13692 /* find the knapsack constraint handler */
13693 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13694 if( conshdlr == NULL )
13695 {
13696 SCIPerrorMessage("knapsack constraint handler not found\n");
13697 return SCIP_PLUGINNOTFOUND;
13698 }
13699
13700 /* check whether all variables are binary */
13701 assert(vars != NULL || nvars == 0);
13702 for( i = 0; i < nvars; ++i )
13703 {
13704 if( !SCIPvarIsBinary(vars[i]) )
13705 {
13706 SCIPerrorMessage("item <%s> is not binary\n", SCIPvarGetName(vars[i]));
13707 return SCIP_INVALIDDATA;
13708 }
13709 }
13710
13711 /* get event handler */
13712 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13713 assert(conshdlrdata != NULL);
13714 assert(conshdlrdata->eventhdlr != NULL);
13715
13716 /* create constraint data */
13717 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13718
13719 /* create constraint */
13720 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13721 local, modifiable, dynamic, removable, stickingatnode) );
13722
13723 /* catch events for variables */
13724 if( SCIPisTransformed(scip) )
13725 {
13726 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13727 }
13728
13729 return SCIP_OKAY;
13730}
13731/**! [SnippetConsCreationKnapsack] */
13732
13733/** creates and captures a knapsack constraint
13734 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13735 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13736 *
13737 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13738 *
13739 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13740 */
13742 SCIP* scip, /**< SCIP data structure */
13743 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13744 const char* name, /**< name of constraint */
13745 int nvars, /**< number of items in the knapsack */
13746 SCIP_VAR** vars, /**< array with item variables */
13747 SCIP_Longint* weights, /**< array with item weights */
13748 SCIP_Longint capacity /**< capacity of knapsack */
13749 )
13750{
13751 assert(scip != NULL);
13752
13753 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13755
13756 return SCIP_OKAY;
13757}
13758
13759/** adds new item to knapsack constraint */
13761 SCIP* scip, /**< SCIP data structure */
13762 SCIP_CONS* cons, /**< constraint data */
13763 SCIP_VAR* var, /**< item variable */
13764 SCIP_Longint weight /**< item weight */
13765 )
13766{
13767 assert(var != NULL);
13768 assert(scip != NULL);
13769
13770 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13771 {
13772 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13773 return SCIP_INVALIDDATA;
13774 }
13775
13776 SCIP_CALL( addCoef(scip, cons, var, weight) );
13777
13778 return SCIP_OKAY;
13779}
13780
13781/** gets the capacity of the knapsack constraint */
13783 SCIP* scip, /**< SCIP data structure */
13784 SCIP_CONS* cons /**< constraint data */
13785 )
13786{
13787 SCIP_CONSDATA* consdata;
13788
13789 assert(scip != NULL);
13790
13791 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13792 {
13793 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13794 SCIPABORT();
13795 return 0; /*lint !e527*/
13796 }
13797
13798 consdata = SCIPconsGetData(cons);
13799 assert(consdata != NULL);
13800
13801 return consdata->capacity;
13802}
13803
13804/** changes capacity of the knapsack constraint
13805 *
13806 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13807 */
13809 SCIP* scip, /**< SCIP data structure */
13810 SCIP_CONS* cons, /**< constraint data */
13811 SCIP_Longint capacity /**< new capacity of knapsack */
13812 )
13813{
13814 SCIP_CONSDATA* consdata;
13815
13816 assert(scip != NULL);
13817
13818 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13819 {
13820 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13821 return SCIP_INVALIDDATA;
13822 }
13823
13825 {
13826 SCIPerrorMessage("method can only be called during problem creation stage\n");
13827 return SCIP_INVALIDDATA;
13828 }
13829
13830 consdata = SCIPconsGetData(cons);
13831 assert(consdata != NULL);
13832
13833 consdata->capacity = capacity;
13834
13835 return SCIP_OKAY;
13836}
13837
13838/** gets the number of items in the knapsack constraint */
13840 SCIP* scip, /**< SCIP data structure */
13841 SCIP_CONS* cons /**< constraint data */
13842 )
13843{
13844 SCIP_CONSDATA* consdata;
13845
13846 assert(scip != NULL);
13847
13848 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13849 {
13850 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13851 SCIPABORT();
13852 return -1; /*lint !e527*/
13853 }
13854
13855 consdata = SCIPconsGetData(cons);
13856 assert(consdata != NULL);
13857
13858 return consdata->nvars;
13859}
13860
13861/** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13863 SCIP* scip, /**< SCIP data structure */
13864 SCIP_CONS* cons /**< constraint data */
13865 )
13866{
13867 SCIP_CONSDATA* consdata;
13868
13869 assert(scip != NULL);
13870
13871 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13872 {
13873 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13874 SCIPABORT();
13875 return NULL; /*lint !e527*/
13876 }
13877
13878 consdata = SCIPconsGetData(cons);
13879 assert(consdata != NULL);
13880
13881 return consdata->vars;
13882}
13883
13884/** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13886 SCIP* scip, /**< SCIP data structure */
13887 SCIP_CONS* cons /**< constraint data */
13888 )
13889{
13890 SCIP_CONSDATA* consdata;
13891
13892 assert(scip != NULL);
13893
13894 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13895 {
13896 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13897 SCIPABORT();
13898 return NULL; /*lint !e527*/
13899 }
13900
13901 consdata = SCIPconsGetData(cons);
13902 assert(consdata != NULL);
13903
13904 return consdata->weights;
13905}
13906
13907/** gets the dual solution of the knapsack constraint in the current LP */
13909 SCIP* scip, /**< SCIP data structure */
13910 SCIP_CONS* cons /**< constraint data */
13911 )
13912{
13913 SCIP_CONSDATA* consdata;
13914
13915 assert(scip != NULL);
13916
13917 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13918 {
13919 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13920 SCIPABORT();
13921 return SCIP_INVALID; /*lint !e527*/
13922 }
13923
13924 consdata = SCIPconsGetData(cons);
13925 assert(consdata != NULL);
13926
13927 if( consdata->row != NULL )
13928 return SCIProwGetDualsol(consdata->row);
13929 else
13930 return 0.0;
13931}
13932
13933/** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13935 SCIP* scip, /**< SCIP data structure */
13936 SCIP_CONS* cons /**< constraint data */
13937 )
13938{
13939 SCIP_CONSDATA* consdata;
13940
13941 assert(scip != NULL);
13942
13943 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13944 {
13945 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13946 SCIPABORT();
13947 return SCIP_INVALID; /*lint !e527*/
13948 }
13949
13950 consdata = SCIPconsGetData(cons);
13951 assert(consdata != NULL);
13952
13953 if( consdata->row != NULL )
13954 return SCIProwGetDualfarkas(consdata->row);
13955 else
13956 return 0.0;
13957}
13958
13959/** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13960 * the user must not modify the row!
13961 */
13963 SCIP* scip, /**< SCIP data structure */
13964 SCIP_CONS* cons /**< constraint data */
13965 )
13966{
13967 SCIP_CONSDATA* consdata;
13968
13969 assert(scip != NULL);
13970
13971 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13972 {
13973 SCIPerrorMessage("constraint is not a knapsack\n");
13974 SCIPABORT();
13975 return NULL; /*lint !e527*/
13976 }
13977
13978 consdata = SCIPconsGetData(cons);
13979 assert(consdata != NULL);
13980
13981 return consdata->row;
13982}
13983
13984/** creates and returns the row of the given knapsack constraint */
13986 SCIP* scip, /**< SCIP data structure */
13987 SCIP_CONS* cons /**< constraint data */
13988 )
13989{
13990 SCIP_CONSDATA* consdata;
13991 int i;
13992
13993 assert(scip != NULL);
13994
13995 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13996 {
13997 SCIPerrorMessage("constraint is not a knapsack\n");
13998 SCIPABORT();
13999 return SCIP_ERROR; /*lint !e527*/
14000 }
14001
14002 consdata = SCIPconsGetData(cons);
14003 assert(consdata != NULL);
14004 assert(consdata->row == NULL);
14005
14006 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
14007 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
14009
14010 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
14011 for( i = 0; i < consdata->nvars; ++i )
14012 {
14013 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
14014 }
14015 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
14016
14017 return SCIP_OKAY;
14018}
14019
14020/** cleans up (multi-)aggregations and fixings from knapsack constraints */
14022 SCIP* scip, /**< SCIP data structure */
14023 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
14024 SCIP_Bool* infeasible, /**< pointer to return whether the problem was detected to be infeasible */
14025 int* ndelconss /**< pointer to count number of deleted constraints */
14026 )
14027{
14028 SCIP_CONSHDLR* conshdlr;
14029 SCIP_CONS** conss;
14030 int nconss;
14031 int i;
14032
14033 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14034 if( conshdlr == NULL )
14035 return SCIP_OKAY;
14036
14037 assert(infeasible != NULL);
14038 *infeasible = FALSE;
14039
14040 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
14041 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
14042
14043 /* loop backwards since then deleted constraints do not interfere with the loop */
14044 for( i = nconss - 1; i >= 0; --i )
14045 {
14046 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
14047
14048 if( *infeasible )
14049 break;
14050
14051 if( SCIPconsGetData(conss[i])->nvars >= 1 )
14052 continue;
14053
14054 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
14055 ++(*ndelconss);
14056 }
14057
14058 return SCIP_OKAY;
14059}
#define EVENTHDLR_NAME
SCIP_VAR * h
SCIP_VAR * w
SCIP_VAR ** b
#define EVENTHDLR_DESC
#define DEFAULT_DUALPRESOLVING
Definition cons_and.c:110
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:97
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:90
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:89
#define CONSHDLR_DESC
Definition cons_and.c:86
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:100
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:94
#define DEFAULT_PRESOLPAIRWISE
Definition cons_and.c:105
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:87
#define DEFAULT_PRESOLUSEHASHING
Definition cons_and.c:113
#define MINGAINPERNMINCOMPARISONS
Definition cons_and.c:115
#define CONSHDLR_PROPFREQ
Definition cons_and.c:91
#define NMINCOMPARISONS
Definition cons_and.c:114
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:99
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:92
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:95
#define CONSHDLR_NAME
Definition cons_and.c:85
#define CONSHDLR_DELAYPROP
Definition cons_and.c:96
constraint handler for cardinality constraints
#define DEFAULT_MAXROUNDSROOT
#define DEFAULT_MAXSEPACUTSROOT
#define DEFAULT_MAXSEPACUTS
#define DEFAULT_MAXROUNDS
#define LINCONSUPGD_PRIORITY
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
GUBConsstatus
@ GUBCONSSTATUS_BELONGSTOSET_GF
@ GUBCONSSTATUS_UNINITIAL
@ GUBCONSSTATUS_BELONGSTOSET_GR
@ GUBCONSSTATUS_BELONGSTOSET_GOC1
@ GUBCONSSTATUS_BELONGSTOSET_GNC1
@ GUBCONSSTATUS_BELONGSTOSET_GC2
static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
#define DEFAULT_SEPACARDFREQ
static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
#define KNAPSACKRELAX_MAXDELTA
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
#define DEFAULT_USEGUBS
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
#define KNAPSACKRELAX_MAXSCALE
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define DEFAULT_DETECTCUTOFFBOUND
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
struct SCIP_GUBSet SCIP_GUBSET
static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
static SCIP_RETCODE createNormalizedKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
struct sortkeypair SORTKEYPAIR
#define DEFAULT_NEGATEDCLIQUE
enum GUBVarstatus GUBVARSTATUS
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define DEFAULT_MAXCARDBOUNDDIST
#define MAXCOVERSIZEITERLEWI
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
static void sortItems(SCIP_CONSDATA *consdata)
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
#define HASHSIZE_KNAPSACKCONS
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
static SCIP_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
#define MAX_CLIQUELENGTH
#define DEFAULT_CLQPARTUPDATEFAC
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
#define IDX(j, d)
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
static SCIP_RETCODE sequentialUpAndDownLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *varsM1, int *varsM2, int *varsF, int *varsR, int nvarsM1, int nvarsM2, int nvarsF, int nvarsR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs)
struct SCIP_GUBCons SCIP_GUBCONS
static SCIP_RETCODE separateSequLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_SOL *sol, SCIP_GUBSET *gubset, SCIP_Bool *cutoff, int *ncuts)
#define GUBCONSGROWVALUE
static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
static SCIP_RETCODE greedyCliqueAlgorithm(SCIP *const scip, SCIP_VAR **items, SCIP_Longint *weights, int nitems, SCIP_Longint capacity, SCIP_Bool sorteditems, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
#define DEFAULT_CLIQUEEXTRACTFACTOR
#define DEFAULT_SIMPLIFYINEQUALITIES
static SCIP_RETCODE eventdataFree(SCIP *scip, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE getLiftingSequence(SCIP *scip, SCIP_Real *solvals, SCIP_Longint *weights, int *varsF, int *varsC2, int *varsR, int nvarsF, int nvarsC2, int nvarsR)
#define MAXNCLIQUEVARSCOMP
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE simplifyInequalities(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss, SCIP_Bool *cutoff)
enum GUBConsstatus GUBCONSSTATUS
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
static SCIP_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
static SCIP_RETCODE tightenWeights(SCIP *scip, SCIP_CONS *cons, SCIP_PRESOLTIMING presoltiming, int *nchgcoefs, int *nchgsides, int *naddconss, int *ndelconss, SCIP_Bool *cutoff)
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
#define KNAPSACKRELAX_MAXDNOM
#define USESUPADDLIFT
#define MAXABSVBCOEF
#define MAX_USECLIQUES_SIZE
#define DEFAULT_UPDATECLIQUEPARTITIONS
GUBVarstatus
@ GUBVARSTATUS_BELONGSTOSET_F
@ GUBVARSTATUS_BELONGSTOSET_C1
@ GUBVARSTATUS_BELONGSTOSET_R
@ GUBVARSTATUS_BELONGSTOSET_C2
@ GUBVARSTATUS_CAPACITYEXCEEDED
@ GUBVARSTATUS_UNINITIAL
static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define DEFAULT_DISAGGREGATION
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
#define DEFAULT_DETECTLOWERBOUND
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
#define EVENTTYPE_KNAPSACK
#define MAX_ZEROITEMS_SIZE
Constraint handler for knapsack constraints of the form , x binary and .
Constraint handler for linear constraints in their most general form, .
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
Constraint handler for the set partitioning / packing / covering constraints .
#define NULL
Definition def.h:255
#define SCIP_MAXSTRLEN
Definition def.h:276
#define SCIP_Longint
Definition def.h:148
#define SCIP_MAXTREEDEPTH
Definition def.h:304
#define SCIP_INVALID
Definition def.h:185
#define SCIP_Bool
Definition def.h:98
#define MIN(x, y)
Definition def.h:231
#define SCIP_Real
Definition def.h:163
#define TRUE
Definition def.h:100
#define FALSE
Definition def.h:101
#define MAX(x, y)
Definition def.h:227
#define SCIP_LONGINT_FORMAT
Definition def.h:155
#define SCIPABORT()
Definition def.h:334
#define REALABS(x)
Definition def.h:189
#define SCIP_LONGINT_MAX
Definition def.h:149
#define SCIP_CALL(x)
Definition def.h:362
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateRowKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
SCIP_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible, int *ndelconss)
SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
#define SCIP_DECL_LINCONSUPGD(x)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition scip_copy.c:662
SCIP_Bool SCIPisTransformed(SCIP *scip)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
int SCIPgetNObjVars(SCIP *scip)
Definition scip_prob.c:2616
SCIP_RETCODE SCIPaddConsUpgrade(SCIP *scip, SCIP_CONS *oldcons, SCIP_CONS **newcons)
Definition scip_prob.c:3368
int SCIPgetNContVars(SCIP *scip)
Definition scip_prob.c:2569
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition scip_prob.c:3476
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3420
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3179
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3400
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2348
#define SCIPhashSix(a, b, c, d, e, f)
Definition pub_misc.h:580
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition misc.c:2298
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2596
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2665
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2535
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition scip_prob.c:4289
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:4067
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition scip_prob.c:4178
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsgPrint
#define SCIPdebugMsg
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition misc.c:9197
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition misc.c:9641
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11162
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
int SCIPgetNLPBranchCands(SCIP *scip)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4802
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4350
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:670
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4759
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:492
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition scip_cons.c:281
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:323
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:808
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5046
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:785
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:924
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4320
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:396
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:444
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:693
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4340
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4816
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5276
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:468
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4739
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:762
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:420
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:854
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8423
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8652
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2536
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition cons.c:8845
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition scip_cons.c:1296
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8522
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8702
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition scip_cons.c:1271
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition scip_cons.c:1321
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8582
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:2042
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8454
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8612
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8632
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1812
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:2014
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition scip_cons.c:1524
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition cons.c:8672
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition scip_cons.c:1371
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition scip_cons.c:1346
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1784
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:117
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition scip_cut.c:135
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition scip_event.c:111
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition event.c:1194
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:413
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition event.c:1217
#define SCIPfreeBuffer(scip, ptr)
Definition scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:97
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:424
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:396
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition scip_nlp.c:1058
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition nlp.c:1953
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition scip_nlp.c:954
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1398
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1367
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1429
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1458
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition lp.c:17719
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition lp.c:17917
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition lp.c:17706
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition sepa.c:746
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition sepa.c:913
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition scip_sol.c:1846
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1765
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:469
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
int SCIPgetNSepaRounds(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6401
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition var.c:24483
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition var.c:23535
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5210
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition var.c:23844
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition var.c:23869
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition var.c:24505
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23643
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23479
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition scip_var.c:8882
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition scip_var.c:2119
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24569
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23387
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4386
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *scip, SCIP_VAR **vars, int nvars, int **probtoidxmap, int *probtoidxmapsize, int *cliquepartition, int *ncliques)
Definition scip_var.c:9410
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24269
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:23431
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23901
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition var.c:17551
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6651
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition scip_var.c:728
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24143
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24586
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23653
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:5118
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5296
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2872
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23663
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23268
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *scip, SCIP_VAR **vars, int nvars, int **probtoidxmap, int *probtoidxmapsize, int *cliquepartition, int *ncliques)
Definition scip_var.c:9330
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:24515
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:24525
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23491
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24615
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:2332
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition scip_var.c:2166
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition var.c:23807
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition var.c:23795
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24643
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24235
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition var.c:23444
int SCIPgetNCliques(SCIP *scip)
Definition scip_var.c:9512
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:24495
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24654
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24121
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2736
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17275
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition var.c:17643
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:7412
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition var.c:24557
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition scip_var.c:361
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition scip_var.c:2236
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition var.c:24537
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition var.c:16808
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition var.c:24547
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4328
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition scip_var.c:2199
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24601
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1853
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition scip_var.c:10984
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition var.c:17611
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition var.c:23819
void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10816
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPextendPermsymDetectionGraphLinear(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool *success)
return SCIP_OKAY
int c
int depth
SCIP_Bool cutoff
SCIP_Real objval
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition implics.c:3384
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition implics.c:3374
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition implics.c:3396
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
struct BMS_BlkMem BMS_BLKMEM
Definition memory.h:437
public methods for managing constraints
public methods for managing events
public methods for implications, variable bounds, and cliques
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
#define SCIPdebugPrintCons(x, y, z)
#define SCIPdebugMessage
Definition pub_message.h:96
#define SCIPdebugPrintf
Definition pub_message.h:99
public data structures and miscellaneous methods
methods for selecting (weighted) k-medians
methods for sorting joint arrays of various types
public methods for separators
public methods for problem variables
public methods for branching rule plugins and branching
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
public methods for event handler plugins and event handlers
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for nonlinear relaxation
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
GUBVARSTATUS * gubvarsstatus
GUBCONSSTATUS * gubconsstatus
SCIP_GUBCONS ** gubconss
structs for symmetry computations
methods for dealing with symmetry detection graphs
@ SCIP_CONFTYPE_PROPAGATION
#define SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(x)
Definition type_cons.h:956
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:938
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
#define SCIP_DECL_CONSEXIT(x)
Definition type_cons.h:136
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:867
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:201
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:769
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
struct SYM_Graph SYM_GRAPH
Definition type_cons.h:68
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:506
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:885
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:612
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:691
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:845
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:706
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:561
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:676
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:810
#define SCIP_DECL_CONSINIT(x)
Definition type_cons.h:126
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
#define SCIP_DECL_CONSDELVARS(x)
Definition type_cons.h:753
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:179
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition type_event.h:79
#define SCIP_EVENTTYPE_VARFIXED
Definition type_event.h:72
#define SCIP_EVENTTYPE_VARDELETED
Definition type_event.h:71
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition type_event.h:160
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_LBRELAXED
Definition type_event.h:78
#define SCIP_EVENTTYPE_FORMAT
Definition type_event.h:157
#define SCIP_EVENTTYPE_IMPLADDED
Definition type_event.h:85
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition type_event.h:77
@ SCIP_EXPRCURV_LINEAR
Definition type_expr.h:65
struct SCIP_Clique SCIP_CLIQUE
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:58
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:60
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:195
#define SCIP_DECL_HASHGETKEY(x)
Definition type_misc.h:192
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:198
struct SCIP_HashTable SCIP_HASHTABLE
Definition type_misc.h:88
struct SCIP_NlRow SCIP_NLROW
Definition type_nlp.h:41
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDDATA
@ SCIP_PLUGINNOTFOUND
@ SCIP_NOMEMORY
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Sepa SCIP_SEPA
Definition type_sepa.h:51
@ SCIP_STAGE_PROBLEM
Definition type_set.h:45
@ SCIP_STAGE_INITSOLVE
Definition type_set.h:52
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
@ SCIP_STAGE_TRANSFORMING
Definition type_set.h:46
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
enum SYM_Symtype SYM_SYMTYPE
@ SYM_SYMTYPE_SIGNPERM
@ SYM_SYMTYPE_PERM
#define SCIP_PRESOLTIMING_MEDIUM
Definition type_timing.h:53
unsigned int SCIP_PRESOLTIMING
Definition type_timing.h:61
#define SCIP_PRESOLTIMING_FAST
Definition type_timing.h:52
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition type_timing.h:54
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARSTATUS_FIXED
Definition type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_VARSTATUS_NEGATED
Definition type_var.h:57
@ SCIP_VARSTATUS_AGGREGATED
Definition type_var.h:55
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141